@chakra-ui/react#Tr JavaScript Examples

The following examples show how to use @chakra-ui/react#Tr. 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: Table.js    From web-client with Apache License 2.0 6 votes vote down vote up
CommandsTable = ({ commands, onDeleteCallback = null }) => {
    return <Table>
        <Thead>
            <Tr>
                <Th style={{ width: '190px' }}>Name</Th>
                <Th className='only-desktop'>Description</Th>
                <Th>Execution environment</Th>
                <Th>Output parser</Th>
                <Th>&nbsp;</Th>
            </Tr>
        </Thead>
        <Tbody>
            {null === commands && <LoadingTableRow numColumns={5} />}
            {null !== commands && 0 === commands.length && <NoResultsTableRow numColumns={5} />}
            {null !== commands && 0 !== commands.length && commands.map(command =>
                <Tr key={command.id}>
                    <Td><CommandBadge command={command} /></Td>
                    <Td className="only-desktop">
                        {command.description}<br />
                        <Tags values={command.tags} />
                    </Td>
                    <Td>{command.executable_type === 'custom' ? 'Host' : 'Container'}</Td>
                    <Td>{command.output_parser ?? '-'}</Td>
                    <Td textAlign="right">
                        <LinkButton href={`/commands/${command.id}/edit`}>Edit</LinkButton>
                        {onDeleteCallback && <DeleteIconButton onClick={() => onDeleteCallback(command.id)} />}
                    </Td>
                </Tr>
            )}
        </Tbody>
    </Table>
}
Example #2
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 #3
Source File: RecentActivityWidget.js    From web-client with Apache License 2.0 6 votes vote down vote up
RecentActivityWidget = () => {
    const [auditLog] = useFetch('/auditlog?limit=5');

    return <DashboardWidget title="Recent activity">

        {auditLog && auditLog.length > 0 ?
            <Table>
                <Thead>
                    <Tr>
                        <Th>Action</Th>
                        <Th>User</Th>
                        <Th>Date/Time</Th>
                    </Tr>
                </Thead>
                <Tbody>
                    {auditLog.map(log => <Tr key={log.id}>
                        <Td><Badge>{log.action}</Badge></Td>
                        <Td>{log.user_name ?
                            <UserLink userId={log.user_id}>{log.user_name}</UserLink> : '-'}</Td>
                        <Td>{log.insert_ts}</Td>
                    </Tr>)}
                </Tbody>
            </Table> :
            <p>No activity to show.</p>
        }
    </DashboardWidget>
}
Example #4
Source File: components.js    From idena-web with MIT License 6 votes vote down vote up
export function FlipsHiddenDescRow({children}) {
  return (
    <Tr display={['table-row', 'none']}>
      <Td colSpan={3} px={0} pt={1} pb={3}>
        <Box bg="gray.50" borderRadius="md" px={5} py={2}>
          {children}
        </Box>
      </Td>
    </Tr>
  )
}
Example #5
Source File: Table.js    From web-client with Apache License 2.0 6 votes vote down vote up
NotesTable = ({ notes, onDeleteButtonClick }) => {
    return <Table>
        <Thead>
            <Tr>
                <Th>Content</Th>
                <Th style={{ width: '200px' }}>Creation time</Th>
                <Th style={{ width: '140px' }}>Author</Th>
                <Th style={{ width: '140px' }}>Visibility</Th>
                <Th>&nbsp;</Th>
            </Tr>
        </Thead>
        <Tbody>
            {notes.length === 0 && <NoResultsTableRow numColumns={5} />}
            {notes.map((note, index) =>
                <Tr>
                    <Td><ReactMarkdown>{note.content}</ReactMarkdown></Td>
                    <Td><ReactTimeAgo date={note.insert_ts} /></Td>
                    <Td><UserLink userId={note.user_id}>{note.user_name}</UserLink></Td>
                    <Td><VisibilityLegend visibility={note.visibility} /></Td>
                    <Td>
                        <RestrictedComponent roles={['administrator', 'superuser', 'user']}>
                            <DeleteIconButton onClick={ev => onDeleteButtonClick(ev, note)} />
                        </RestrictedComponent>
                    </Td>
                </Tr>
            )}
        </Tbody>
    </Table>
}
Example #6
Source File: TechStack.js    From benjamincarlson.io with MIT License 5 votes vote down vote up
TechStack = () => {
    const { colorMode } = useColorMode()

    const colorSecondary = {
        light: 'gray.600',
        dark: 'gray.400'
    }

    const linkColor = {
        light: 'blue.400',
        dark: 'blue.600'
    }

    return (
        <Box as="section" w="100%" mt={10} mb={20}>
            <Heading letterSpacing="tight" size="lg" fontWeight={700} as="h2" mb={4}>
                Tech Stack ⚙️
            </Heading>
            <Text color={colorSecondary[colorMode]} mb={4}>Each piece of technology used in this website is carefully thought out. I believe this is one of the best stacks there is to build websites of any size and domain.</Text>
            <Box flexDir="column" overflowX="auto">
                <Table variant="simple">
                    <Thead>
                        <Tr>
                            <Th>Type</Th>
                            <Th>Name</Th>
                            <Th>Route</Th>
                            <Th>Description</Th>
                        </Tr>
                    </Thead>
                    <Tbody>
                        <Tr>
                            <Td>JS Framework</Td>
                            <Td><Link href="https://nextjs.org" color={linkColor[colorMode]} isExternal>Next JS</Link></Td>
                            <Td>n/a</Td>
                            <Td>Next.js was an easy choice given its large community and ability for rapid development.</Td>
                        </Tr>
                        <Tr>
                            <Td>CSS Framework</Td>
                            <Td><Link href="https://chakra-ui.com" color={linkColor[colorMode]} isExternal>Chakra UI</Link></Td>
                            <Td>n/a</Td>
                            <Td>I use Chakra UI because its components make a beautiful UI out of the box and are highly customizable.</Td>
                        </Tr>
                        <Tr>
                            <Td>Blog</Td>
                            <Td><Code>next-mdx-remote</Code></Td>
                            <Td>/blog/[slug].js</Td>
                            <Td>I use <Link href="https://github.com/hashicorp/next-mdx-remote" color={linkColor[colorMode]} isExternal>next-mdx-remote</Link> for my blog. Posts are stored in <Code>mdx</Code> files and pre-rendered.</Td>
                        </Tr>
                        <Tr>
                            <Td>Real-Time Statistics</Td>
                            <Td>Next.js api routes</Td>
                            <Td>/api/[].js</Td>
                            <Td>Multiple api routes that interact with the GitHub, YouTube, and Strava api to fetch my real-time social media data using Next.JS <Link href="https://nextjs.org/docs/api-routes/introduction" color={linkColor[colorMode]} isExternal>serverless functions</Link>.</Td>
                        </Tr>
                        <Tr>
                            <Td>Realtime Blog Post View/Like Count</Td>
                            <Td>Firebase Realtime Db</Td>
                            <Td>/api</Td>
                            <Td>I use <Link href="https://firebase.google.com" color={linkColor[colorMode]} isExternal>Google's Firebase</Link> to store view and like counts for my blog posts.</Td>
                        </Tr>
                        <Tr>
                            <Td>Deployment</Td>
                            <Td>Vercel</Td>
                            <Td>n/a</Td>
                            <Td>I use <Link href="https://vercel.com" color={linkColor[colorMode]} isExternal>Vercel</Link> to deploy my app. It's free, fast, integrates with GitHub, and overall a great experience.</Td>
                        </Tr>
                        <Tr>
                            <Td>Domain</Td>
                            <Td>Namecheap</Td>
                            <Td>n/a</Td>
                            <Td>My domain name is bought and stored through <Link color="blue.500" href="https://www.namecheap.com/" isExternal>Namecheap</Link>.</Td>
                        </Tr>
                    </Tbody>
                </Table>
            </Box>
        </Box>
    )
}
Example #7
Source File: ActivityView.jsx    From scaffold-directory with MIT License 5 votes vote down vote up
export default function ActivityView() {
  const [eventsFeed, setEventFeeds] = useState([]);
  const [isLoadingEvents, setIsLoadingEvents] = useState(false);
  const { secondaryFontColor } = useCustomColorModes();

  useEffect(() => {
    const updateEvents = async () => {
      setIsLoadingEvents(true);
      const events = await getAllEvents(25);
      setEventFeeds(events);
      setIsLoadingEvents(false);
    };

    updateEvents();
  }, []);

  return (
    <Container maxW="container.md" centerContent>
      <Heading as="h1" mb="4">
        Activity feed
      </Heading>
      <Text color={secondaryFontColor} textAlign="center" mb={10}>
        Last 25 things happening at SRE.
      </Text>
      {isLoadingEvents ? (
        <Box w="100%" maxW="500px">
          <SkeletonText mt="4" noOfLines={10} spacing="4" />
        </Box>
      ) : (
        <Table>
          <Thead>
            <Tr>
              <Th>Builder</Th>
              <Th>Time</Th>
              <Th>Action</Th>
            </Tr>
          </Thead>
          <Tbody>
            {eventsFeed.map(event => (
              <EventRow key={`${event.timestamp}_${event.payload.userAddress}`} event={event} />
            ))}
          </Tbody>
        </Table>
      )}
    </Container>
  );
}
Example #8
Source File: Cart.js    From react-sample-projects with MIT License 5 votes vote down vote up
Cart = () => {
  const dispatch = useDispatch();
  const navigate = useNavigate();
  const cartItems = useSelector(state => state.cart.cartItems);

  const viewProductDetails = (e, item) => {
    navigate(`/product/${item.id}`);
  };

  const deleteItem = (e, item) => {
    e.stopPropagation();
    e.preventDefault();
    dispatch(deleteItemFromCart(item));
  };

  if (cartItems.length === 0) {
    return (
      <Flex>
        <Box
          m={4}
          w="100%"
          fontWeight="semibold"
          letterSpacing="wide"
          textAlign="center"
        >
          You cart empty :(
        </Box>
      </Flex>
    );
  }
  return (
    <Box m={3} p={3}>
      <Table variant="simple">
        <Thead>
          <Tr>
            <Th>#</Th>
            <Th>Image</Th>
            <Th>Title</Th>
            <Th isNumeric>Price</Th>
            <Th isNumeric>Quantity</Th>
            <Th>Action</Th>
          </Tr>
        </Thead>
        <Tbody>
          {cartItems.map((item, index) => (
            <Tr key={item.id} onClick={e => viewProductDetails(e, item)}>
              <Td>{index + 1}</Td>
              <Td>
                <Avatar size={'sm'} src={item.image} alt={item.title} />
              </Td>
              <Td>{item.title}</Td>
              <Td isNumeric>
                ${parseFloat(item.price * item.quantity).toFixed(2)}
              </Td>
              <Td isNumeric>{item.quantity}</Td>
              <Td>
                <Button onClick={e => deleteItem(e, item)}>Delete</Button>
              </Td>
            </Tr>
          ))}
        </Tbody>
      </Table>
    </Box>
  );
}
Example #9
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 #10
Source File: SubmissionReviewTableSkeleton.jsx    From scaffold-directory with MIT License 5 votes vote down vote up
ChallengesTableSkeleton = () => (
  <Box overflowX="auto">
    <Table mb={4}>
      <Thead>
        <Tr>
          <Th>Builder</Th>
          <Th>Challenge</Th>
          <Th>Contract</Th>
          <Th>Live demo</Th>
          <Th>Submitted time</Th>
          <Th>Actions</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={4} />
              </Td>
              <Td>
                <SkeletonText noOfLines={1} py={4} />
              </Td>
              <Td>
                <SkeletonText noOfLines={1} py={4} />
              </Td>
              <Td>
                <SkeletonText noOfLines={1} py={4} />
              </Td>
              <Td>
                <Skeleton startColor="blue.100" endColor="blue.500">
                  <Button type="button" size="xs">
                    Review
                  </Button>
                </Skeleton>
              </Td>
            </Tr>
          );
        })}
      </Tbody>
    </Table>
  </Box>
)
Example #11
Source File: [id].js    From idena-web with MIT License 4 votes vote down vote up
export default function Details() {
  const {t} = useTranslation()
  const router = useRouter()
  const isDesktop = useIsDesktop()

  const [flipView, setFlipView] = useState({
    isOpen: false,
  })

  const {id} = router.query

  const {data, isFetching} = useQuery(
    ['get-certificate-full', id],
    () => getCertificate(id, 1),
    {
      enabled: !!id,
      retry: false,
      refetchOnWindowFocus: false,
      initialData: {
        shortFlips: [],
        longFlips: [],
      },
    }
  )

  const openFlipView = (
    hash,
    answer,
    isCorrect,
    withWords,
    isCorrectReport,
    shouldBeReported
  ) => {
    setFlipView({
      isOpen: true,
      hash,
      answer,
      isCorrect,
      withWords,
      isCorrectReport,
      shouldBeReported,
    })
  }

  return (
    <Layout>
      <Page py={0}>
        <Flex direction="column" flex={1} alignSelf="stretch" pb={10}>
          <Flex
            align="center"
            alignSelf="stretch"
            justify="space-between"
            mt={[4, 8]}
          >
            <AngleArrowBackIcon
              stroke="#578FFF"
              display={['block', 'none']}
              position="absolute"
              left={4}
              top={4}
              h="28px"
              w="28px"
              onClick={() => {
                router.push('/try')
              }}
            />
            <PageTitleNew>{t('Training validation report')}</PageTitleNew>
            <CloseButton
              display={['none', 'flex']}
              alignSelf="flex-start"
              onClick={() => {
                router.push('/try')
              }}
            />
          </Flex>
          <Flex width={['100%', '720px']} direction="column">
            {data.actionType === CertificateActionType.Passed && (
              <AlertBox>
                <Flex align="center">
                  <RightIcon boxSize={[5, 4]} color="green.500" mr={[3, 2]} />
                  <Text fontWeight={500}>{t('Passed successfully')}</Text>
                </Flex>
              </AlertBox>
            )}
            {data.actionType === CertificateActionType.Failed && (
              <AlertBox borderColor="red.050" bg="red.010">
                <Flex align="center">
                  <WarningIcon boxSize={4} color="red.500" mr={2} />
                  <Text fontWeight={500}>{t('Failed. Please try again')}</Text>
                </Flex>
              </AlertBox>
            )}
            <Flex
              direction={['column', 'row']}
              justifyContent="space-between"
              fontSize="md"
              align="center"
              mt={8}
            >
              <Flex direction={['column', 'row']} w={['100%', 'auto']}>
                <DetailsPoints
                  title={t('Short score')}
                  isLoading={isFetching}
                  value={`${data.shortScore || 0}/6`}
                  isFailed={data.shortScore < 4}
                />
                <DetailsPoints
                  title={t('Long score')}
                  isLoading={isFetching}
                  value={`${data.longScore || 0}/18`}
                  isFailed={data.longScore < 14}
                />
                <DetailsPoints
                  title={t('Reporting score')}
                  isLoading={isFetching}
                  value={`${data.reportScore || 0}/6`}
                  isFailed={data.reportScore < 4}
                  mb={[8, 0]}
                />
              </Flex>
              {data.actionType === CertificateActionType.Passed && (
                <Flex w={['100%', 'auto']}>
                  {isDesktop ? (
                    <TextLink
                      href="/certificate/[id]"
                      as={`/certificate/${id}`}
                      fontWeight={500}
                      mr={4}
                      target="_blank"
                    >
                      <CertificateIcon boxSize={5} mr={1} />
                      {t('Show certificate')}
                    </TextLink>
                  ) : (
                    <WideLink
                      href={`/certificate/${id}`}
                      target="_blank"
                      label={t('Show certificate')}
                    >
                      <Box
                        boxSize={8}
                        backgroundColor="brandBlue.10"
                        borderRadius="10px"
                      >
                        <CertificateIcon boxSize={5} mr={1} mt="6px" ml="6px" />
                      </Box>
                    </WideLink>
                  )}
                </Flex>
              )}
            </Flex>
            <Heading
              fontSize={['md', 'lg']}
              fontWeight="500"
              color={['muted', 'brandGray.500']}
              mt={[10, 8]}
            >
              {t('Short session')}
            </Heading>
            <Flex mt={[0, 5]}>
              <Table>
                <Thead display={['none', 'table-header-group']}>
                  <Tr>
                    <RoundedFlipsTh>
                      {t('Flips')}
                      <FlipsThCorner borderLeftRadius="md" />
                    </RoundedFlipsTh>
                    <RoundedFlipsTh w={32}>
                      {t('Answers')}
                      <FlipsThCorner borderRightRadius="md" />
                    </RoundedFlipsTh>
                  </Tr>
                </Thead>
                <Tbody>
                  {isFetching
                    ? new Array(6).fill(0).map((_, idx) => (
                        <Tr key={idx}>
                          <Td colSpan={2} px={0} py={2}>
                            <Skeleton h={7} />
                          </Td>
                        </Tr>
                      ))
                    : data.shortFlips.map(({hash, answer, correct}) => (
                        <Tr key={hash}>
                          <FlipsValueTd>
                            <ShortFlipWithIcon
                              hash={hash}
                              onClick={() =>
                                openFlipView(hash, answer, correct)
                              }
                            />
                          </FlipsValueTd>
                          <FlipsValueTd w={['60px', 'auto']}>
                            <Flex alignItems="center">
                              {correct ? (
                                <RightIcon color="green.500" boxSize={5} />
                              ) : (
                                <WrongIcon color="red.500" boxSize={5} />
                              )}
                              <Flex fontSize={['base', 'md']} ml={[1, 2]}>
                                {GetAnswerTitle(t, answer)}
                              </Flex>
                            </Flex>
                          </FlipsValueTd>
                        </Tr>
                      ))}
                </Tbody>
              </Table>
            </Flex>
            <Heading
              fontSize={['md', 'lg']}
              fontWeight="500"
              color={['muted', 'brandGray.500']}
              mt={[10, 8]}
            >
              {t('Long session')}
            </Heading>
            <Flex mt={[0, 5]}>
              <Table style={{tableLayout: 'fixed'}}>
                <Thead display={['none', 'table-header-group']}>
                  <Tr>
                    <RoundedFlipsTh w="35%">
                      {t('Flips')}
                      <FlipsThCorner borderLeftRadius="md" />
                    </RoundedFlipsTh>
                    <FlipsTh w={32}>{t('Answers')}</FlipsTh>
                    <FlipsTh>{t('Qualification')}</FlipsTh>
                    <RoundedFlipsTh>
                      {t('Reporting reason')}
                      <FlipsThCorner borderRightRadius="md" />
                    </RoundedFlipsTh>
                  </Tr>
                </Thead>
                <Tbody>
                  {isFetching
                    ? new Array(6).fill(0).map((_, idx) => (
                        <Tr key={idx}>
                          <Td colSpan={4} px={0} py={2}>
                            <Skeleton h={7} />
                          </Td>
                        </Tr>
                      ))
                    : data.longFlips.map(
                        ({
                          hash,
                          answer,
                          correct,
                          correctReport,
                          wrongWords,
                          reason,
                        }) => (
                          <>
                            <Tr position={['relative', 'initial']} key={hash}>
                              <FlipsValueTd
                                borderBottom={[0, '1px solid #e8eaed']}
                              >
                                <LongFlipWithIcon
                                  hash={hash}
                                  onClick={() =>
                                    openFlipView(
                                      hash,
                                      answer,
                                      correct,
                                      true,
                                      correctReport,
                                      reason !== 0
                                    )
                                  }
                                />
                              </FlipsValueTd>
                              <FlipsValueTd
                                borderBottom={[0, '1px solid #e8eaed']}
                                w={['75px', 'auto']}
                              >
                                <Flex direction={['column', 'row']}>
                                  <Flex alignItems="center">
                                    {correct ? (
                                      <RightIcon
                                        color="green.500"
                                        boxSize={5}
                                      />
                                    ) : (
                                      <WrongIcon color="red.500" boxSize={5} />
                                    )}
                                    <Text
                                      textOverflow="ellipsis"
                                      overflow="hidden"
                                      whiteSpace="nowrap"
                                      fontSize={['base', 'md']}
                                      ml={[1, 2]}
                                    >
                                      {GetAnswerTitle(t, answer)}
                                    </Text>
                                  </Flex>
                                  <Text
                                    display={['block', 'none']}
                                    color="muted"
                                    fontSize="md"
                                    fontWeight={500}
                                  >
                                    {t('Answer')}
                                  </Text>
                                </Flex>
                              </FlipsValueTd>
                              <FlipsValueTd
                                borderBottom={[0, '1px solid #e8eaed']}
                                w={['90px', 'auto']}
                              >
                                <Flex direction={['column', 'row']}>
                                  <Flex alignItems="center">
                                    {correctReport ? (
                                      <RightIcon
                                        color="green.500"
                                        boxSize={5}
                                      />
                                    ) : (
                                      <WrongIcon color="red.500" boxSize={5} />
                                    )}
                                    <Text
                                      textOverflow="ellipsis"
                                      overflow="hidden"
                                      whiteSpace="nowrap"
                                      fontSize={['base', 'md']}
                                      ml={[1, 2]}
                                    >
                                      {wrongWords
                                        ? t('Reported')
                                        : t('Not reported')}
                                    </Text>
                                  </Flex>
                                  <Text
                                    display={['block', 'none']}
                                    color="muted"
                                    fontSize="md"
                                    fontWeight={500}
                                  >
                                    {t('Qualification')}
                                  </Text>
                                </Flex>
                              </FlipsValueTd>
                              <FlipsValueTd display={['none', 'table-cell']}>
                                {GetReasonDesc(t, reason)}
                              </FlipsValueTd>
                            </Tr>
                            <FlipsHiddenDescRow>
                              <Flex
                                direction="column"
                                w="100%"
                                onClick={() =>
                                  openFlipView(
                                    hash,
                                    answer,
                                    correct,
                                    true,
                                    correctReport,
                                    reason !== 0
                                  )
                                }
                              >
                                <Text fontSize="base" fontWeight={500}>
                                  {GetReasonDesc(t, reason)}
                                </Text>
                                <Text
                                  color="muted"
                                  fontSize="md"
                                  fontWeight={500}
                                >
                                  {t('Reason')}
                                </Text>
                              </Flex>
                            </FlipsHiddenDescRow>
                          </>
                        )
                      )}
                </Tbody>
              </Table>
            </Flex>
          </Flex>
        </Flex>
        <FlipView {...flipView} onClose={() => setFlipView({isOpen: false})} />
      </Page>
    </Layout>
  )
}
Example #12
Source File: VaultItemEdit.js    From web-client with Apache License 2.0 4 votes vote down vote up
VaultItemEdit = () => {
    const { projectId, vaultItemId } = useParams();
    const navigate = useNavigate();

    const [item, setVaultItem] = useState(new Vault());
    const [password, setPassword] = useState(null);

    const onVaultItemFormChange = ev => {
        const value = ev.target.type === 'checkbox' ? ev.target.checked : ev.target.value;
        setVaultItem({ ...item, [ev.target.name]: value });
    }

    const onFormSubmit = ev => {
        ev.preventDefault();

        item.password = password;

        secureApiFetch(`/vault/${projectId}/${vaultItemId}`, { method: 'PUT', body: JSON.stringify(item) })
            .then(resp => {
                if (resp.status === 201) {
                    setVaultItem(new Vault());
                    setPassword(null);
                    actionCompletedToast(`The vault item has been modified.`);
                    navigate(`/projects/${projectId}`);
                } else {
                    errorToast("The vault item could not be saved. Review the form data or check the application logs.")
                }
            })
    }

    const onPasswordProvided = ev => {
        ev.preventDefault();

        secureApiFetch(`/vault/${projectId}/${vaultItemId}`, { method: 'POST', body: JSON.stringify({ 'password': password }) })
            .then(response => response.json())
            .then(json => {
                if (json['success'] === false) {
                    errorToast("Seems like a wrong password.");
                    setPassword(null);
                }
                else {
                    var newItem = new Vault();
                    newItem.name = json['name'];
                    newItem.note = json['note'];
                    newItem.value = json['value'];
                    newItem.type = json['type'];
                    newItem.reportable = json['reportable'];
                    setVaultItem(newItem);
                    actionCompletedToast(`The vault item "${newItem.name}" has been loaded.`);
                }
            })
            .catch(err => {
                errorToast(err);
                setPassword(null);
            })
    }

    const onPasswordFormChanged = ev => {
        setPassword(ev.target.value);
    }

    return <div>
        {item.name !== "" && <>
            <form onSubmit={onFormSubmit}>
                <h3>Vault item</h3>
                <Table>
                    <Thead>
                        <Tr>
                            <Th>Type</Th>
                            <Th>Name</Th>
                            <Th>Note</Th>
                            <Th>Value</Th>
                            <Th>Reportable</Th>
                            <Th>&nbsp;</Th>
                        </Tr>
                    </Thead>
                    <Tbody>
                        <Tr>
                            <Td>
                                <Select name="type" onChange={onVaultItemFormChange} value={item.type || ""} isRequired>
                                    <option value="password">Password</option>
                                    <option value="note">Note</option>
                                    <option value="token">Token</option>
                                    <option value="key">Key</option>
                                </Select>
                            </Td>
                            <Td>
                                <Input type="text" name="name" onChange={onVaultItemFormChange} value={item.name || ""} isRequired />
                            </Td>
                            <Td>
                                <Input type="text" name="note" onChange={onVaultItemFormChange} value={item.note || ""} />
                            </Td>
                            <Td>
                                <Input type="text" name="value" onChange={onVaultItemFormChange} value={item.value || ""} isRequired />
                            </Td>
                            <Td>
                                <Checkbox name="reportable" onChange={onVaultItemFormChange} isChecked={item.reportable} />
                            </Td>
                            <Td>
                                <Button type="submit">Update</Button>
                            </Td>
                        </Tr>
                    </Tbody>
                </Table>
            </form>
        </>}
        {item.name === "" && <>
            <h3>Please provide password</h3>
            <form onSubmit={onPasswordProvided}>
                <Input type="password" name="password" onChange={onPasswordFormChanged} value={password || ""} isRequired />
                <Button type="submit">Send</Button>
            </form>
        </>}
    </div>
}
Example #13
Source File: view.js    From idena-web with MIT License 4 votes vote down vote up
export default function ViewVotingPage() {
  const {t, i18n} = useTranslation()

  const [, {addVote}] = useDeferredVotes()

  const toast = useToast()

  const {
    query: {id},
    push: redirect,
  } = useRouter()

  const {epoch} = useEpoch() ?? {epoch: -1}

  const {coinbase, privateKey} = useAuthState()
  const {
    data: {balance: identityBalance},
  } = useBalance()

  const [current, send, service] = useMachine(viewVotingMachine, {
    actions: {
      onError: (context, {data: {message}}) => {
        toast({
          status: 'error',
          // eslint-disable-next-line react/display-name
          render: () => (
            <Toast title={humanError(message, context)} status="error" />
          ),
        })
      },
      addVote: (_, {data: {vote}}) => addVote(vote),
    },
  })

  React.useEffect(() => {
    send('RELOAD', {id, epoch, address: coinbase})
  }, [coinbase, epoch, id, send])

  const toDna = toLocaleDna(i18n.language)

  const {
    title,
    desc,
    contractHash,
    status,
    balance = 0,
    contractBalance = Number(balance),
    votingMinPayment = 0,
    publicVotingDuration = 0,
    quorum = 20,
    committeeSize,
    options = [],
    votes = [],
    voteProofsCount,
    finishDate,
    finishCountingDate,
    selectedOption,
    winnerThreshold = 50,
    balanceUpdates,
    ownerFee,
    totalReward,
    estimatedOracleReward,
    estimatedMaxOracleReward = estimatedOracleReward,
    isOracle,
    minOracleReward,
    estimatedTotalReward,
    pendingVote,
    adCid,
    issuer,
  } = current.context

  const [
    {canProlong, canFinish, canTerminate, isFetching: actionsIsFetching},
    refetchActions,
  ] = useOracleActions(id)

  const isLoaded = !current.matches('loading')

  const sameString = a => b => areSameCaseInsensitive(a, b)

  const eitherIdleState = (...states) =>
    eitherState(current, ...states.map(s => `idle.${s}`.toLowerCase())) ||
    states.some(sameString(status))

  const isClosed = eitherIdleState(
    VotingStatus.Archived,
    VotingStatus.Terminated
  )

  const didDetermineWinner = hasWinner({
    votes,
    votesCount: voteProofsCount,
    winnerThreshold,
    quorum,
    committeeSize,
    finishCountingDate,
  })

  const isMaxWinnerThreshold = winnerThreshold === 100

  const accountableVoteCount = sumAccountableVotes(votes)

  const {data: ad} = useIpfsAd(adCid)

  const adPreviewDisclosure = useDisclosure()

  const isValidAdVoting = React.useMemo(
    () => validateAdVoting({ad, voting: current.context}) === false,
    [ad, current.context]
  )

  const isMaliciousAdVoting = ad && isValidAdVoting

  return (
    <>
      <Layout showHamburger={false}>
        <Page pt={8}>
          <Stack spacing={10}>
            <VotingSkeleton isLoaded={isLoaded} h={6}>
              <Stack isInline spacing={2} align="center">
                <VotingStatusBadge status={status} fontSize="md">
                  {t(mapVotingStatus(status))}
                </VotingStatusBadge>
                <Box
                  as={VotingBadge}
                  bg="gray.100"
                  color="muted"
                  fontSize="md"
                  cursor="pointer"
                  pl="1/2"
                  transition="color 0.2s ease"
                  _hover={{
                    color: 'brandGray.500',
                  }}
                  onClick={() => {
                    openExternalUrl(
                      `https://scan.idena.io/contract/${contractHash}`
                    )
                  }}
                >
                  <Stack isInline spacing={1} align="center">
                    <Avatar size={5} address={contractHash} />
                    <Text>{contractHash}</Text>
                  </Stack>
                </Box>
                <CloseButton
                  sx={{
                    '&': {
                      marginLeft: 'auto!important',
                    },
                  }}
                  onClick={() => redirect('/oracles/list')}
                />
              </Stack>
            </VotingSkeleton>
            <Stack isInline spacing={10} w="full">
              <Box minWidth="lg" maxW="lg">
                <Stack spacing={6}>
                  <VotingSkeleton isLoaded={isLoaded}>
                    <Stack
                      spacing={8}
                      borderRadius="md"
                      bg="gray.50"
                      py={8}
                      px={10}
                    >
                      <Stack spacing={4}>
                        <Heading
                          overflow="hidden"
                          fontSize={21}
                          fontWeight={500}
                          display="-webkit-box"
                          sx={{
                            '&': {
                              WebkitBoxOrient: 'vertical',
                              WebkitLineClamp: '2',
                            },
                          }}
                        >
                          {isMaliciousAdVoting
                            ? t('Please reject malicious ad')
                            : title}
                        </Heading>
                        {ad ? (
                          <>
                            {isMaliciousAdVoting ? (
                              <MaliciousAdOverlay>
                                <OracleAdDescription ad={ad} />
                              </MaliciousAdOverlay>
                            ) : (
                              <OracleAdDescription ad={ad} />
                            )}
                          </>
                        ) : (
                          <Text
                            isTruncated
                            lineHeight="tall"
                            whiteSpace="pre-wrap"
                          >
                            <Linkify
                              onClick={url => {
                                send('FOLLOW_LINK', {url})
                              }}
                            >
                              {desc}
                            </Linkify>
                          </Text>
                        )}
                      </Stack>
                      <Flex>
                        {adCid && (
                          <IconButton
                            icon={<ViewIcon boxSize={4} />}
                            _hover={{background: 'transparent'}}
                            onClick={adPreviewDisclosure.onOpen}
                          >
                            {t('Preview')}
                          </IconButton>
                        )}
                        <GoogleTranslateButton
                          phrases={[
                            title,
                            desc &&
                              encodeURIComponent(desc?.replace(/%/g, '%25')),
                            options.map(({value}) => value).join('\n'),
                          ]}
                          locale={i18n.language}
                          alignSelf="start"
                        />
                      </Flex>
                      <Divider orientation="horizontal" />
                      {isLoaded && <VotingPhase service={service} />}
                    </Stack>
                  </VotingSkeleton>

                  {eitherIdleState(
                    VotingStatus.Pending,
                    VotingStatus.Starting,
                    VotingStatus.Open,
                    VotingStatus.Voting,
                    VotingStatus.Voted,
                    VotingStatus.Prolonging
                  ) && (
                    <VotingSkeleton isLoaded={isLoaded}>
                      {isMaliciousAdVoting ? (
                        <>
                          {eitherIdleState(VotingStatus.Voted) ? (
                            <Box>
                              <Text color="muted" fontSize="sm" mb={3}>
                                {t('Choose an option to vote')}
                              </Text>
                              <Stack spacing={3}>
                                {/* eslint-disable-next-line no-shadow */}
                                {options.map(({id, value}) => {
                                  const isMine = id === selectedOption
                                  return (
                                    <Stack
                                      isInline
                                      spacing={2}
                                      align="center"
                                      bg={isMine ? 'blue.012' : 'gray.50'}
                                      borderRadius="md"
                                      minH={8}
                                      px={3}
                                      py={2}
                                      zIndex={1}
                                    >
                                      <Flex
                                        align="center"
                                        justify="center"
                                        bg={
                                          isMine
                                            ? 'brandBlue.500'
                                            : 'transparent'
                                        }
                                        borderRadius="full"
                                        borderWidth={isMine ? 0 : '4px'}
                                        borderColor="gray.100"
                                        color="white"
                                        w={4}
                                        h={4}
                                      >
                                        {isMine && <OkIcon boxSize={3} />}
                                      </Flex>

                                      <Text
                                        isTruncated
                                        maxW="sm"
                                        title={value.length > 50 ? value : ''}
                                      >
                                        {value}
                                      </Text>
                                    </Stack>
                                  )
                                })}
                              </Stack>
                            </Box>
                          ) : null}
                        </>
                      ) : (
                        <Box>
                          <Text color="muted" fontSize="sm" mb={3}>
                            {t('Choose an option to vote')}
                          </Text>
                          {eitherIdleState(VotingStatus.Voted) ? (
                            <Stack spacing={3}>
                              {/* eslint-disable-next-line no-shadow */}
                              {options.map(({id, value}) => {
                                const isMine = id === selectedOption
                                return (
                                  <Stack
                                    isInline
                                    spacing={2}
                                    align="center"
                                    bg={isMine ? 'blue.012' : 'gray.50'}
                                    borderRadius="md"
                                    minH={8}
                                    px={3}
                                    py={2}
                                    zIndex={1}
                                  >
                                    <Flex
                                      align="center"
                                      justify="center"
                                      bg={
                                        isMine ? 'brandBlue.500' : 'transparent'
                                      }
                                      borderRadius="full"
                                      borderWidth={isMine ? 0 : '4px'}
                                      borderColor="gray.100"
                                      color="white"
                                      w={4}
                                      h={4}
                                    >
                                      {isMine && <OkIcon boxSize={3} />}
                                    </Flex>

                                    <Text
                                      isTruncated
                                      maxW="sm"
                                      title={value.length > 50 ? value : ''}
                                    >
                                      {value}
                                    </Text>
                                  </Stack>
                                )
                              })}
                            </Stack>
                          ) : (
                            <RadioGroup
                              value={String(selectedOption)}
                              onChange={value => {
                                send('SELECT_OPTION', {
                                  option: Number(value),
                                })
                              }}
                            >
                              <Stack spacing={2}>
                                {/* eslint-disable-next-line no-shadow */}
                                {options.map(({id, value}) => (
                                  <VotingOption
                                    key={id}
                                    value={String(id)}
                                    isDisabled={eitherIdleState(
                                      VotingStatus.Pending,
                                      VotingStatus.Starting,
                                      VotingStatus.Voted
                                    )}
                                    annotation={
                                      isMaxWinnerThreshold
                                        ? null
                                        : t('{{count}} min. votes required', {
                                            count: toPercent(
                                              winnerThreshold / 100
                                            ),
                                          })
                                    }
                                  >
                                    {value}
                                  </VotingOption>
                                ))}
                              </Stack>
                            </RadioGroup>
                          )}
                        </Box>
                      )}
                    </VotingSkeleton>
                  )}

                  {eitherIdleState(
                    VotingStatus.Counting,
                    VotingStatus.Finishing,
                    VotingStatus.Archived,
                    VotingStatus.Terminating,
                    VotingStatus.Terminated
                  ) && (
                    <VotingSkeleton isLoaded={isLoaded}>
                      <Stack spacing={3}>
                        <Text color="muted" fontSize="sm">
                          {t('Voting results')}
                        </Text>
                        <VotingResult votingService={service} spacing={3} />
                      </Stack>
                    </VotingSkeleton>
                  )}

                  <VotingSkeleton isLoaded={!actionsIsFetching}>
                    <Flex justify="space-between" align="center">
                      <Stack isInline spacing={2}>
                        {eitherIdleState(VotingStatus.Pending) && (
                          <PrimaryButton
                            loadingText={t('Launching')}
                            onClick={() => {
                              send('REVIEW_START_VOTING', {
                                from: coinbase,
                              })
                            }}
                          >
                            {t('Launch')}
                          </PrimaryButton>
                        )}

                        {eitherIdleState(VotingStatus.Open) &&
                          (isOracle ? (
                            <PrimaryButton
                              onClick={() => {
                                if (isMaliciousAdVoting) {
                                  send('FORCE_REJECT')
                                }
                                send('REVIEW')
                              }}
                            >
                              {isMaliciousAdVoting ? t('Reject') : t('Vote')}
                            </PrimaryButton>
                          ) : (
                            <Box>
                              <Tooltip
                                label={t(
                                  'This vote is not available to you. Only validated identities randomly selected to the committee can vote.'
                                )}
                                placement="top"
                                zIndex="tooltip"
                              >
                                <PrimaryButton isDisabled>
                                  {t('Vote')}
                                </PrimaryButton>
                              </Tooltip>
                            </Box>
                          ))}

                        {eitherIdleState(VotingStatus.Counting) && canFinish && (
                          <PrimaryButton
                            isLoading={current.matches(
                              `mining.${VotingStatus.Finishing}`
                            )}
                            loadingText={t('Finishing')}
                            onClick={() => send('FINISH', {from: coinbase})}
                          >
                            {didDetermineWinner
                              ? t('Finish voting')
                              : t('Claim refunds')}
                          </PrimaryButton>
                        )}

                        {eitherIdleState(
                          VotingStatus.Open,
                          VotingStatus.Voting,
                          VotingStatus.Voted,
                          VotingStatus.Counting
                        ) &&
                          canProlong && (
                            <PrimaryButton
                              onClick={() => send('REVIEW_PROLONG_VOTING')}
                            >
                              {t('Prolong voting')}
                            </PrimaryButton>
                          )}

                        {(eitherIdleState(
                          VotingStatus.Voted,
                          VotingStatus.Voting
                        ) ||
                          (eitherIdleState(VotingStatus.Counting) &&
                            !canProlong &&
                            !canFinish)) && (
                          <PrimaryButton as={Box} isDisabled>
                            {t('Vote')}
                          </PrimaryButton>
                        )}

                        {!eitherIdleState(
                          VotingStatus.Terminated,
                          VotingStatus.Terminating
                        ) &&
                          canTerminate && (
                            <PrimaryButton
                              colorScheme="red"
                              variant="solid"
                              _active={{}}
                              onClick={() => send('TERMINATE')}
                            >
                              {t('Terminate')}
                            </PrimaryButton>
                          )}
                      </Stack>

                      <Stack isInline spacing={3} align="center">
                        {eitherIdleState(
                          VotingStatus.Archived,
                          VotingStatus.Terminated
                        ) &&
                          !didDetermineWinner && (
                            <Text color="red.500">
                              {t('No winner selected')}
                            </Text>
                          )}
                        <VDivider />
                        <Stack isInline spacing={2} align="center">
                          {didDetermineWinner ? (
                            <UserTickIcon color="muted" boxSize={4} />
                          ) : (
                            <UserIcon color="muted" boxSize={4} />
                          )}

                          <Text as="span">
                            {/* eslint-disable-next-line no-nested-ternary */}
                            {eitherIdleState(VotingStatus.Counting) ? (
                              <>
                                {t('{{count}} published votes', {
                                  count: accountableVoteCount,
                                })}{' '}
                                {t('out of {{count}}', {
                                  count: voteProofsCount,
                                })}
                              </>
                            ) : eitherIdleState(
                                VotingStatus.Pending,
                                VotingStatus.Open,
                                VotingStatus.Voting,
                                VotingStatus.Voted
                              ) ? (
                              t('{{count}} votes', {
                                count: voteProofsCount,
                              })
                            ) : (
                              t('{{count}} published votes', {
                                count: accountableVoteCount,
                              })
                            )}
                          </Text>
                        </Stack>
                      </Stack>
                    </Flex>
                  </VotingSkeleton>

                  <VotingSkeleton isLoaded={isLoaded}>
                    <Stack spacing={5}>
                      <Box>
                        <Text fontWeight={500}>{t('Recent transactions')}</Text>
                      </Box>
                      <Table style={{tableLayout: 'fixed', fontWeight: 500}}>
                        <Thead>
                          <Tr>
                            <RoundedTh isLeft>{t('Transaction')}</RoundedTh>
                            <RoundedTh>{t('Date and time')}</RoundedTh>
                            <RoundedTh isRight textAlign="right">
                              {t('Amount')}
                            </RoundedTh>
                          </Tr>
                        </Thead>
                        <Tbody>
                          {balanceUpdates.map(
                            ({
                              hash,
                              type,
                              timestamp,
                              from,
                              amount,
                              fee,
                              tips,
                              balanceChange = 0,
                              contractCallMethod,
                            }) => {
                              const isSender = areSameCaseInsensitive(
                                from,
                                coinbase
                              )

                              const txCost =
                                (isSender ? -amount : 0) + balanceChange
                              const totalTxCost =
                                txCost - ((isSender ? fee : 0) + tips)

                              const isCredit = totalTxCost > 0

                              const color =
                                // eslint-disable-next-line no-nested-ternary
                                totalTxCost === 0
                                  ? 'brandGray.500'
                                  : isCredit
                                  ? 'blue.500'
                                  : 'red.500'

                              return (
                                <Tr key={hash}>
                                  <OraclesTxsValueTd>
                                    <Stack isInline>
                                      <Flex
                                        align="center"
                                        justify="center"
                                        bg={isCredit ? 'blue.012' : 'red.012'}
                                        color={color}
                                        borderRadius="lg"
                                        minH={8}
                                        minW={8}
                                      >
                                        {isSender ? (
                                          <ArrowUpIcon boxSize={5} />
                                        ) : (
                                          <ArrowDownIcon boxSize={5} />
                                        )}
                                      </Flex>
                                      <Box isTruncated>
                                        {contractCallMethod ? (
                                          <Text>
                                            {
                                              ContractCallMethod[
                                                contractCallMethod
                                              ]
                                            }
                                          </Text>
                                        ) : (
                                          <Text>
                                            {ContractTransactionType[type]}
                                          </Text>
                                        )}
                                        <SmallText isTruncated title={from}>
                                          {hash}
                                        </SmallText>
                                      </Box>
                                    </Stack>
                                  </OraclesTxsValueTd>
                                  <OraclesTxsValueTd>
                                    <Text>
                                      {new Date(timestamp).toLocaleString()}
                                    </Text>
                                  </OraclesTxsValueTd>
                                  <OraclesTxsValueTd textAlign="right">
                                    <Text
                                      color={color}
                                      overflowWrap="break-word"
                                    >
                                      {toLocaleDna(i18n.language, {
                                        signDisplay: 'exceptZero',
                                      })(txCost)}
                                    </Text>
                                    {isSender && (
                                      <SmallText>
                                        {t('Fee')} {toDna(fee + tips)}
                                      </SmallText>
                                    )}
                                  </OraclesTxsValueTd>
                                </Tr>
                              )
                            }
                          )}
                          {balanceUpdates.length === 0 && (
                            <Tr>
                              <OraclesTxsValueTd colSpan={3}>
                                <FillCenter py={12}>
                                  <Stack spacing={4} align="center">
                                    <CoinsLgIcon
                                      boxSize={20}
                                      color="gray.100"
                                    />

                                    <Text color="muted">
                                      {t('No transactions')}
                                    </Text>
                                  </Stack>
                                </FillCenter>
                              </OraclesTxsValueTd>
                            </Tr>
                          )}
                        </Tbody>
                      </Table>
                    </Stack>
                  </VotingSkeleton>
                </Stack>
              </Box>
              <VotingSkeleton isLoaded={isLoaded} h={isLoaded ? 'auto' : 'lg'}>
                <Box mt={3}>
                  <Box mt={-2} mb={4}>
                    <IconButton
                      icon={<RefreshIcon boxSize={5} />}
                      px={1}
                      pr={3}
                      _focus={null}
                      onClick={() => {
                        send('REFRESH')
                        refetchActions()
                      }}
                    >
                      {t('Refresh')}
                    </IconButton>
                  </Box>
                  {!isClosed && (
                    <Stat mb={8}>
                      <StatLabel as="div" color="muted" fontSize="md">
                        <Stack isInline spacing={2} align="center">
                          <StarIcon boxSize={4} color="white" />
                          <Text fontWeight={500}>{t('Prize pool')}</Text>
                        </Stack>
                      </StatLabel>
                      <StatNumber fontSize="base" fontWeight={500}>
                        {toDna(estimatedTotalReward)}
                      </StatNumber>
                      <Box mt={1}>
                        <IconButton
                          icon={<AddFundIcon boxSize={5} />}
                          onClick={() => {
                            send('ADD_FUND')
                          }}
                        >
                          {t('Add funds')}
                        </IconButton>
                      </Box>
                    </Stat>
                  )}
                  <Stack spacing={6}>
                    {!isClosed && (
                      <Stat>
                        <StatLabel color="muted" fontSize="md">
                          <Tooltip
                            label={
                              // eslint-disable-next-line no-nested-ternary
                              Number(votingMinPayment) > 0
                                ? isMaxWinnerThreshold
                                  ? t('Deposit will be refunded')
                                  : t(
                                      'Deposit will be refunded if your vote matches the majority'
                                    )
                                : t('Free voting')
                            }
                            placement="top"
                          >
                            <Text
                              as="span"
                              borderBottom="dotted 1px"
                              borderBottomColor="muted"
                              cursor="help"
                            >
                              {t('Voting deposit')}
                            </Text>
                          </Tooltip>
                        </StatLabel>
                        <StatNumber fontSize="base" fontWeight={500}>
                          {toDna(votingMinPayment)}
                        </StatNumber>
                      </Stat>
                    )}
                    {!isClosed && (
                      <Stat>
                        <StatLabel color="muted" fontSize="md">
                          <Tooltip
                            label={t('Including your Voting deposit')}
                            placement="top"
                          >
                            <Text
                              as="span"
                              borderBottom="dotted 1px"
                              borderBottomColor="muted"
                              cursor="help"
                            >
                              {t('Min reward')}
                            </Text>
                          </Tooltip>
                        </StatLabel>
                        <StatNumber fontSize="base" fontWeight={500}>
                          {toDna(estimatedOracleReward)}
                        </StatNumber>
                      </Stat>
                    )}
                    {!isClosed && (
                      <Stat>
                        <StatLabel color="muted" fontSize="md">
                          {isMaxWinnerThreshold ? (
                            <Text as="span">{t('Your max reward')}</Text>
                          ) : (
                            <Tooltip
                              label={t(
                                `Including a share of minority voters' deposit`
                              )}
                              placement="top"
                            >
                              <Text
                                as="span"
                                borderBottom="dotted 1px"
                                borderBottomColor="muted"
                                cursor="help"
                              >
                                {t('Max reward')}
                              </Text>
                            </Tooltip>
                          )}
                        </StatLabel>
                        <StatNumber fontSize="base" fontWeight={500}>
                          {toDna(estimatedMaxOracleReward)}
                        </StatNumber>
                      </Stat>
                    )}
                    <AsideStat
                      label={t('Committee size')}
                      value={t('{{committeeSize}} oracles', {committeeSize})}
                    />
                    <AsideStat
                      label={t('Quorum required')}
                      value={t('{{count}} votes', {
                        count: quorumVotesCount({quorum, committeeSize}),
                      })}
                    />
                    <AsideStat
                      label={t('Majority threshold')}
                      value={
                        isMaxWinnerThreshold
                          ? t('N/A')
                          : toPercent(winnerThreshold / 100)
                      }
                    />
                    {isClosed && totalReward && (
                      <AsideStat
                        label={t('Prize paid')}
                        value={toDna(totalReward)}
                      />
                    )}
                  </Stack>
                </Box>
              </VotingSkeleton>
            </Stack>
          </Stack>
        </Page>
      </Layout>

      <VoteDrawer
        isOpen={
          eitherState(current, 'review', `mining.${VotingStatus.Voting}`) &&
          !eitherState(
            current,
            `mining.${VotingStatus.Voting}.reviewPendingVote`
          )
        }
        onClose={() => {
          send('CANCEL')
        }}
        // eslint-disable-next-line no-shadow
        option={options.find(({id}) => id === selectedOption)?.value}
        from={coinbase}
        to={contractHash}
        deposit={votingMinPayment}
        publicVotingDuration={publicVotingDuration}
        finishDate={finishDate}
        finishCountingDate={finishCountingDate}
        isLoading={current.matches(`mining.${VotingStatus.Voting}`)}
        onVote={() => {
          send('VOTE', {privateKey})
        }}
      />

      <AddFundDrawer
        isOpen={eitherState(
          current,
          'funding',
          `mining.${VotingStatus.Funding}`
        )}
        onClose={() => {
          send('CANCEL')
        }}
        from={coinbase}
        to={contractHash}
        available={identityBalance}
        ownerFee={ownerFee}
        isLoading={current.matches(`mining.${VotingStatus.Funding}`)}
        onAddFund={({amount}) => {
          send('ADD_FUND', {amount, privateKey})
        }}
      />

      <LaunchDrawer
        isOpen={eitherState(
          current,
          `idle.${VotingStatus.Pending}.review`,
          `mining.${VotingStatus.Starting}`
        )}
        onClose={() => {
          send('CANCEL')
        }}
        balance={contractBalance}
        requiredBalance={votingMinBalance(minOracleReward, committeeSize)}
        ownerFee={ownerFee}
        from={coinbase}
        available={identityBalance}
        isLoading={current.matches(`mining.${VotingStatus.Starting}`)}
        onLaunch={({amount}) => {
          send('START_VOTING', {amount, privateKey})
        }}
      />

      <FinishDrawer
        isOpen={eitherState(
          current,
          `idle.${VotingStatus.Counting}.finish`,
          `mining.${VotingStatus.Finishing}`
        )}
        onClose={() => {
          send('CANCEL')
        }}
        from={coinbase}
        available={identityBalance}
        isLoading={current.matches(`mining.${VotingStatus.Finishing}`)}
        onFinish={() => {
          send('FINISH', {privateKey})
        }}
        hasWinner={didDetermineWinner}
      />

      <ProlongDrawer
        isOpen={eitherState(
          current,
          'prolong',
          `mining.${VotingStatus.Prolonging}`
        )}
        onClose={() => {
          send('CANCEL')
        }}
        from={coinbase}
        available={identityBalance}
        isLoading={current.matches(`mining.${VotingStatus.Prolonging}`)}
        onProlong={() => {
          send('PROLONG_VOTING', {privateKey})
        }}
      />

      <TerminateDrawer
        isOpen={eitherState(
          current,
          `idle.terminating`,
          `mining.${VotingStatus.Terminating}`
        )}
        onClose={() => {
          send('CANCEL')
        }}
        contractAddress={contractHash}
        isLoading={current.matches(`mining.${VotingStatus.Terminating}`)}
        onTerminate={() => {
          send('TERMINATE', {privateKey})
        }}
      />

      {pendingVote && (
        <ReviewNewPendingVoteDialog
          isOpen={eitherState(
            current,
            `mining.${VotingStatus.Voting}.reviewPendingVote`
          )}
          onClose={() => {
            send('GOT_IT')
          }}
          vote={pendingVote}
          startCounting={finishDate}
          finishCounting={finishCountingDate}
        />
      )}

      {adCid && (
        <AdPreview
          ad={{...ad, author: issuer}}
          isMalicious={isMaliciousAdVoting}
          {...adPreviewDisclosure}
        />
      )}

      <Dialog
        isOpen={eitherIdleState('redirecting')}
        onClose={() => send('CANCEL')}
      >
        <DialogHeader>{t('Leaving Idena')}</DialogHeader>
        <DialogBody>
          <Text>{t(`You're about to leave Idena.`)}</Text>
          <Text>{t(`Are you sure?`)}</Text>
        </DialogBody>
        <DialogFooter>
          <SecondaryButton onClick={() => send('CANCEL')}>
            {t('Cancel')}
          </SecondaryButton>
          <PrimaryButton onClick={() => send('CONTINUE')}>
            {t('Continue')}
          </PrimaryButton>
        </DialogFooter>
      </Dialog>
    </>
  )
}
Example #14
Source File: List.js    From web-client with Apache License 2.0 4 votes vote down vote up
ReportTemplatesList = () => {
    const [templates, refetchTemplates] = useFetch('/reports/templates')

    const destroy = useDelete('/reports/', refetchTemplates);

    const deleteTemplate = (ev, templateId) => {
        ev.stopPropagation();

        destroy(templateId);
    }

    const { isOpen: isAddReportTemplateDialogOpen, onOpen: openAddReportTemplateDialog, onClose: closeAddReportTemplateDialog } = useDisclosure();

    const onReportTemplateFormSaved = () => {
        refetchTemplates();
        closeAddReportTemplateDialog();
    }

    const handleDownload = (reportId) => {
        secureApiFetch(`/attachments/${reportId}`, { method: 'GET', headers: {} })
            .then(resp => {
                const contentDispositionHeader = resp.headers.get('Content-Disposition');
                const filenameRe = new RegExp(/filename="(.*)";/)
                const filename = filenameRe.exec(contentDispositionHeader)[1]
                return Promise.all([resp.blob(), filename]);
            })
            .then((values) => {
                const blob = values[0];
                const filename = values[1];
                const url = URL.createObjectURL(blob);
                const a = document.createElement('a');
                a.href = url;
                a.download = filename;
                a.click();
            })
    }

    const safeResolveMime = mimeType => {
        try {
            return resolveMime(mimeType)['name']
        } catch (err) {
            console.error(err);
            return mimeType;
        }
    }
    return <>
        <PageTitle value="Report templates" />
        <div className='heading'>
            <Breadcrumb>
                <Link to="/reports">Reports</Link>
            </Breadcrumb>

            <ReportModalDialog isOpen={isAddReportTemplateDialogOpen} onSubmit={onReportTemplateFormSaved} onCancel={closeAddReportTemplateDialog} />
            <CreateButton onClick={openAddReportTemplateDialog}>Add report template...</CreateButton>
        </div>
        <Title title='Report templates' icon={<IconDocumentDuplicate />} />

        <Alert status="info">
            <AlertIcon />
            Needing some inspiration? Have a look at hundred of penetration test reports available at&nbsp;<ExternalLink href="http://pentestreports.com/">http://pentestreports.com/</ExternalLink>
        </Alert>

        <Alert status="info">
            <AlertIcon />
            Visit this <ExternalLink href={UserManualUrl + 'reports/report-template-variables.html'}>user manual's page</ExternalLink> if you want to find out which variables are available to your report templates.
        </Alert>

        {!templates ? <Loading /> :
            <Table variant="simple">
                <Thead>
                    <Tr>
                        <Th style={{ width: '190px' }}>Name</Th>
                        <Th>Description</Th>
                        <Th style={{ width: '190px' }}>File name</Th>
                        <Th>Mime type</Th>
                        <Th>Downloads</Th>
                        <Th>&nbsp;</Th>
                    </Tr>
                </Thead>
                <Tbody>
                    {templates.length === 0 ?
                        <Tr><Td colSpan={3}><NoResults /></Td></Tr>
                        :
                        templates.map((template) =>
                            <Tr key={template.id}>
                                <Td>{template.version_name}</Td>
                                <Td><EmptyField value={template.version_description} /></Td>
                                <Td>{template.client_file_name}</Td>
                                <Td><span title={safeResolveMime(template.file_mimetype)}>{template.file_mimetype}</span></Td>
                                <Td>
                                    <SecondaryButton onClick={() => handleDownload(template.attachment_id)}>
                                        <IconDocument /> DOCX
                                    </SecondaryButton>
                                </Td>
                                <Td textAlign="right">
                                    <DeleteIconButton disabled={template.generated_by_uid === 0} title={template.generated_by_uid === 0 ? "System templates cannot be deleted" : ""} onClick={ev => deleteTemplate(ev, template.id)} />
                                </Td>
                            </Tr>
                        )
                    }
                </Tbody>
            </Table>
        }
    </>
}
Example #15
Source File: rent.js    From idena-web with MIT License 4 votes vote down vote up
export default function Rent() {
  const router = useRouter()
  const {t} = useTranslation()

  const {coinbase} = useAuthState()

  const buySharedNodeDisclosure = useDisclosure()

  const [state, setState] = useState(0)

  const [checkedProviders, setCheckedProviders] = useState([])

  const {
    data: indexerData,
    isFetched: indexerIsFetched,
    isLoading: indexerIsLoading,
  } = useQuery(['last-block'], () => getLastBlock(), {
    retry: false,
    refetchOnWindowFocus: false,
  })

  const {data: identity, isLoading: identityIsLoading} = useQuery(
    ['fetch-identity', coinbase],
    () => fetchIdentity(coinbase, true),
    {
      enabled: !!coinbase,
      refetchOnWindowFocus: false,
    }
  )

  const {data: providers, isLoading: providersIsLoading} = useQuery(
    ['providers'],
    getProviders,
    {
      initialData: [],
      enabled: !!indexerIsFetched,
      refetchOnWindowFocus: false,
    }
  )

  const indexerLastBlock = indexerData?.height || 0

  useEffect(() => {
    async function updateStatus() {
      const shuffled = shuffle(providers.filter(x => Boolean(x.slots)))
      shuffled.forEach(provider => {
        checkProviderSyncing(provider.data.url)
          .then(response =>
            setCheckedProviders(prev => {
              const blocksLeft = indexerLastBlock - response?.currentBlock
              return mergeProviders(prev, {
                ...provider,
                duration: response.duration,
                blocksLeft,
                status:
                  blocksLeft > SYNCING_DIFF
                    ? ProviderStatus.OutOfSync
                    : ProviderStatus.Success,
              })
            })
          )
          .catch(() =>
            setCheckedProviders(prev =>
              mergeProviders(prev, {
                ...provider,
                duration: MAX_DURATION,
                status: ProviderStatus.Error,
              })
            )
          )
      })
    }
    if (providers.length) updateStatus()
  }, [indexerLastBlock, providers])

  const isLoading = indexerIsLoading || identityIsLoading || providersIsLoading

  const isDesktop = useIsDesktop()

  const {
    isOpen: isOpenRentDetailDrawer,
    onOpen: onOpenRentDetailDrawer,
    onClose: onCloseRentDetailDrawer,
  } = useDisclosure()

  const selectedProvider = checkedProviders.length && checkedProviders[state]

  return (
    <Layout canRedirect={false}>
      <Page mb={14} pt={[4, 6]}>
        <Box w="full">
          <Flex align="center" justify="space-between">
            <AngleArrowBackIcon
              stroke="#578FFF"
              display={['block', 'none']}
              position="absolute"
              left={4}
              top={4}
              h="28px"
              w="28px"
              onClick={() => {
                router.back()
              }}
            />
            <PageTitleNew>{t('Rent a shared node')}</PageTitleNew>
            <CloseButton
              display={['none', 'flex']}
              onClick={() => router.back()}
            />
          </Flex>
          <Box>
            <Table>
              <Thead display={['none', 'table-header-group']}>
                <Tr>
                  <RoundedTh isLeft width={rem(40)}></RoundedTh>
                  <RoundedTh>{t('Node URL')}</RoundedTh>
                  <RoundedTh>{t('Owner')}</RoundedTh>
                  <RoundedTh>{t('Location')}</RoundedTh>
                  <RoundedTh>{t('Latency, sec')}</RoundedTh>
                  <RoundedTh textAlign="right">
                    {t('Slots available')}
                  </RoundedTh>
                  <RoundedTh isRight textAlign="right">
                    {t('Price per validation')}
                  </RoundedTh>
                </Tr>
              </Thead>
              <Tbody>
                {isLoading
                  ? new Array(10).fill(0).map((_, idx) => (
                      <Tr key={idx}>
                        <Td colSpan={7} px={0}>
                          <Skeleton h={[32, 8]} />
                        </Td>
                      </Tr>
                    ))
                  : checkedProviders.map((p, idx) => (
                      <Tr key={idx}>
                        <Td display={['none', 'table-cell']}>
                          <Radio
                            isChecked={state === idx}
                            onClick={() => setState(idx)}
                            borderColor="#d2d4d9"
                          />
                        </Td>
                        <Td
                          borderBottom={['solid 0px', 'solid 1px #e8eaed']}
                          px={[0, 3]}
                          py={[1, 2]}
                        >
                          <Flex
                            direction="column"
                            border={['solid 1px', 'initial']}
                            borderColor={['gray.100', 'inherit']}
                            borderRadius={['8px', 0]}
                            p={[4, 0]}
                            onClick={() => {
                              setState(idx)
                              if (!isDesktop) onOpenRentDetailDrawer()
                            }}
                          >
                            <Flex justifyContent="flex-start">
                              <Flex
                                direction="column"
                                maxW={['100%', 'initial']}
                              >
                                <Text
                                  fontSize={['mdx', 'md']}
                                  fontWeight={[500, 400]}
                                  isTruncated
                                >
                                  {p.data.url}
                                </Text>
                                <ProviderStatusLabel
                                  status={p.status}
                                  blocksLeft={p.blocksLeft}
                                ></ProviderStatusLabel>
                              </Flex>
                              <Flex display="none">
                                <Text
                                  fontSize="mdx"
                                  fontWeight={500}
                                  color="gray.064"
                                >
                                  FILL_RATING
                                </Text>
                                <SoftStarIcon mt="3px" ml="3px" h={4} w={4} />
                              </Flex>
                            </Flex>
                            <Flex
                              display={['flex', 'none']}
                              justifyContent="flex-start"
                            >
                              <Flex
                                direction="column"
                                fontSize="base"
                                color="gray.064"
                                mt={4}
                                w="50%"
                              >
                                <Text>{t('Latency, sec')}</Text>
                                <Flex>
                                  <Text color="gray.500" mr={1}>
                                    {p.status === ProviderStatus.Error
                                      ? '—'
                                      : (p.duration / 1000).toFixed(3)}
                                  </Text>
                                  <Text display="none">/ FILL_SLOTS</Text>
                                </Flex>
                              </Flex>
                              <Flex
                                direction="column"
                                fontSize="base"
                                color="gray.064"
                                mt={4}
                                w="50%"
                              >
                                <Text>Price</Text>
                                <Flex>
                                  <Text color="gray.500">
                                    {GetProviderPrice(
                                      p.data,
                                      identity?.state,
                                      identity?.age
                                    )}{' '}
                                    iDNA
                                  </Text>
                                </Flex>
                              </Flex>
                            </Flex>
                          </Flex>
                        </Td>
                        <Td display={['none', 'table-cell']}>
                          <Link
                            target="_blank"
                            rel="noreferrer"
                            color="brandBlue.100"
                            href={`https://t.me/${p.data.ownerName}`}
                          >
                            {p.data.ownerName}
                          </Link>
                        </Td>
                        <Td display={['none', 'table-cell']}>
                          {p.data.location}
                        </Td>
                        <Td display={['none', 'table-cell']}>
                          {p.status === ProviderStatus.Error
                            ? '—'
                            : (p.duration / 1000).toFixed(3)}
                        </Td>
                        <Td display={['none', 'table-cell']} textAlign="right">
                          {p.slots}
                        </Td>
                        <Td display={['none', 'table-cell']} textAlign="right">
                          {GetProviderPrice(
                            p.data,
                            identity?.state,
                            identity?.age
                          )}{' '}
                          iDNA
                        </Td>
                      </Tr>
                    ))}
              </Tbody>
            </Table>
          </Box>
        </Box>
        <Stack
          display={['none', 'flex']}
          isInline
          spacing={2}
          justify="flex-end"
          bg="white"
          borderTop="1px"
          borderTopColor="gray.100"
          px={4}
          py={3}
          h={14}
          position="fixed"
          bottom={0}
          left={0}
          right={0}
        >
          <SecondaryButton onClick={router.back}>Cancel</SecondaryButton>
          <PrimaryButton onClick={buySharedNodeDisclosure.onOpen}>
            {t('Continue')}
          </PrimaryButton>
        </Stack>
      </Page>

      {selectedProvider && identity && (
        <ProviderInfoDrawer
          p={selectedProvider}
          identity={identity}
          isOpen={isOpenRentDetailDrawer}
          onClose={onCloseRentDetailDrawer}
          onSubmit={buySharedNodeDisclosure.onOpen}
        />
      )}

      <BuySharedNodeForm
        {...buySharedNodeDisclosure}
        providerId={selectedProvider && selectedProvider.id}
        url={selectedProvider && selectedProvider.data.url}
        from={coinbase}
        amount={
          selectedProvider &&
          GetProviderPrice(
            selectedProvider.data,
            identity?.state,
            identity?.age
          )
        }
        to={selectedProvider && selectedProvider.data.address}
      />
    </Layout>
  )
}
Example #16
Source File: List.js    From web-client with Apache License 2.0 4 votes vote down vote up
UsersList = () => {
    const navigate = useNavigate();
    const loggedInUser = Auth.getLoggedInUser();
    const [users, updateUsers] = useFetch("/users");
    const deleteUser = useDelete("/users/", updateUsers);
    const handleCreate = () => {
        navigate("/users/create");
    };

    const [selectedUsers, setSelectedUsers] = useState([]);

    const onTaskCheckboxChange = (ev) => {
        const target = ev.target;
        const targetUserId = parseInt(target.value);
        if (target.checked) {
            setSelectedUsers([...selectedUsers, targetUserId]);
        } else {
            setSelectedUsers(
                selectedUsers.filter(value => value !== targetUserId)
            );
        }
    };

    const handleBulkDelete = () => {
        secureApiFetch(`/users`, {
            method: "PATCH",
            headers: {
                "Bulk-Operation": "DELETE",
            },
            body: JSON.stringify(selectedUsers),
        })
            .then(updateUsers)
            .then(() => {
                setSelectedUsers([]);
                actionCompletedToast("All selected users were deleted.");
            })
            .catch(err => console.error(err));
    };

    const handleDelete = (id) => {
        deleteUser(id);
        updateUsers();
    };

    return <>
        <PageTitle value="Users" />
        <div className="heading">
            <Breadcrumb />
            <ButtonGroup isAttached>
                <CreateButton onClick={handleCreate}>
                    Create user
                </CreateButton>
                <RestrictedComponent roles={['administrator']}>
                    <DeleteButton onClick={handleBulkDelete} disabled={selectedUsers.length === 0}>
                        Delete selected
                    </DeleteButton>
                </RestrictedComponent>
                <Menu>
                    <EllipsisMenuButton />
                    <MenuList>
                        <ExportMenuItem entity="users" />
                    </MenuList>
                </Menu>
            </ButtonGroup>
        </div>
        <Title title="Users and roles" icon={<IconUserGroup />} />
        <Table>
            <Thead>
                <Tr>
                    <Th style={{ width: "32px" }}>&nbsp;</Th>
                    <Th style={{ width: "64px" }}>&nbsp;</Th>
                    <Th>Full name</Th>
                    <Th>Username</Th>
                    <Th>Role</Th>
                    <Th>Active?</Th>
                    <Th>2FA enabled?</Th>
                    <Th>&nbsp;</Th>
                </Tr>
            </Thead>
            <Tbody>
                {null === users && <LoadingTableRow numColumns={8} />}
                {null !== users && 0 === users.length && <NoResultsTableRow numColumns={8} />}
                {null !== users && 0 !== users.length && users.map((user, index) => (
                    <Tr key={index}>
                        <Td>
                            <input
                                type="checkbox"
                                value={user.id}
                                onChange={onTaskCheckboxChange}
                                checked={selectedUsers.includes(user.id)}
                            />
                        </Td>
                        <Td>
                            <UserAvatar email={user.email} />
                        </Td>
                        <Td>
                            <Link to={`/users/${user.id}`}>
                                {user.full_name}
                            </Link>
                        </Td>
                        <Td>
                            <UserLink userId={user.id}>
                                {user.username}
                            </UserLink>
                        </Td>
                        <Td>
                            <UserRoleBadge role={user.role} />
                        </Td>
                        <Td><BooleanText value={user.active} /></Td>
                        <Td><BooleanText value={user.mfa_enabled} /></Td>
                        <Td textAlign="right">
                            <LinkButton href={`/users/${user.id}/edit`}>
                                Edit
                            </LinkButton>
                            <DeleteIconButton
                                onClick={() => handleDelete(user.id)}
                                disabled={
                                    parseInt(user.id) ===
                                        loggedInUser.id
                                        ? "disabled"
                                        : ""
                                }
                            />
                        </Td>
                    </Tr>
                ))}
            </Tbody>
        </Table>
    </>
}
Example #17
Source File: Profile.js    From DAOInsure with MIT License 4 votes vote down vote up
function Profile() {
	const web3Context = useContext(Web3Context);
	const {
		signerAddress,
		userDaoTokenBalance,
		fetchProposals,
		fetchVotedProposals,
		proposalsArray,
		votedProposalsArray,
	} = web3Context;

	const [daoTokenBalance, setDaoTokenBalance] = useState(0);
	const [stable, setStable] = useState(false);

	useEffect(() => {
		setInterval(async () => {
			setDaoTokenBalance(await userDaoTokenBalance());
		}, 10000);
	}, []);

	useEffect(() => {
		fetchProposals();
		fetchVotedProposals();
	}, [stable]);

	function con() {
		console.log(proposalsArray);
	}

	return (
		<VStack
			alignItems='flex-start'
			height='calc(100vh - 64px)'
			px='250px'
			py='20px'
			width='100%'>
			<HStack width='100%' alignItems='flex-start'>
				<Box
					borderWidth='2px'
					borderRadius='full'
					borderColor='whatsapp.500'
					padding='2px'>
					<Avatar
						size='md'
						icon={
							<Jazzicon
								diameter='48'
								address={`${signerAddress}`}
							/>
						}
					/>
				</Box>
				<VStack alignItems='flex-start'>
					<Heading fontSize='20px'>{signerAddress}</Heading>
					<Tag>10DAIx / month</Tag>
				</VStack>
				<Spacer />
				<VStack>
					<Tag>INSURE Tokens : {daoTokenBalance}</Tag>
				</VStack>
			</HStack>
			<Grid
				width='100%'
				mt='30px !important'
				templateColumns='3fr 2fr'
				gridGap={5}
				alignItems='flex-start'>
				<Tabs
					colorScheme='whatsapp'
					variant='soft-rounded'
					width='100%'>
					<TabList>
						<Tab onClick={con}>
							Claims{" "}
							<Tag ml={2} borderRadius='20px'>
								{proposalsArray.length}
							</Tag>
						</Tab>
						<Tab>
							Voted For
							<Tag ml={2} borderRadius='20px'>
								{votedProposalsArray.length}
							</Tag>
						</Tab>
					</TabList>
					<TabPanels>
						<TabPanel mt={3} padding={0}>
							<Card cardTitle='Claims'>
								<Table>
									<Tbody>
										{proposalsArray.map(function (
											element,
											id
										) {
											return (
												<Tr key={id}>
													<Th>
														{" "}
														{element[0].toNumber()}{" "}
													</Th>
													<Th>{element[2]}</Th>
													<Th>
														{element[7] ? (
															<span>
																{" "}
																Passed{" "}
															</span>
														) : (
															<span>
																{" "}
																Failed{" "}
															</span>
														)}
													</Th>
												</Tr>
											);
										})}
									</Tbody>
								</Table>
							</Card>
						</TabPanel>
						<TabPanel mt={3} padding={0}>
							<Card cardTitle='Claims'>
								<Table>
									<Tbody>
										{votedProposalsArray.map(function (
											element,
											id
										) {
											return (
												<Tr key={id}>
													<Th>
														{" "}
														{element[0].toNumber()}{" "}
													</Th>
													<Th>{element[2]}</Th>
													<Th>
														{element[7] ? (
															<span>
																{" "}
																Passed{" "}
															</span>
														) : (
															<span>
																{" "}
																Failed{" "}
															</span>
														)}
													</Th>
												</Tr>
											);
										})}
									</Tbody>
								</Table>
							</Card>
						</TabPanel>
					</TabPanels>
				</Tabs>
			</Grid>
		</VStack>
	);
}
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: validation-report.js    From idena-web with MIT License 4 votes vote down vote up
export default function ValidationReport() {
  const {t, i18n} = useTranslation()

  const {colors} = useTheme()

  const epoch = useEpoch()
  const [identity] = useIdentity()

  const isMobile = useMobile()

  const {address, state, isValidated} = identity

  const {
    prevState,
    lastValidationScore,
    totalScore,
    earnings,
    earningsScore,
    validationReward,
    missedValidationReward,
    invitationReward,
    missedInvitationReward,
    flipReward,
    missedFlipReward,
    flipReportReward,
    missedFlipReportReward,
    totalMissedReward,
    validationResult,
    stakingReward,
    missedStakingReward,
    candidateReward,
    missedCandidateReward,
    isLoading,
  } = useValidationReportSummary()

  const {
    short: {score: shortScore, ...shortResults},
    long: {score: longScore, ...longResults},
  } = lastValidationScore

  const toDna = toLocaleDna(i18n.language, {maximumFractionDigits: 3})

  const maybeDna = amount =>
    !amount || Number.isNaN(amount)
      ? '–'
      : amount.toLocaleString(i18n.language, {maximumFractionDigits: 3})

  const epochNumber = epoch?.epoch

  return (
    <Layout>
      <Page as={Stack} spacing={6}>
        <Flex
          justify="space-between"
          align="center"
          w="full"
          alignItems="center"
        >
          <AngleArrowBackIcon
            stroke="#578FFF"
            position="absolute"
            left={4}
            top={4}
            h="28px"
            w="28px"
            onClick={() => router.back()}
            display={['initial', 'none']}
          />
          <PageTitleNew mb={0} mt={[-2, 0]}>
            {t('Epoch #{{epochNumber}} validation report', {epochNumber})}
          </PageTitleNew>
          <CloseButton
            display={['none', 'initial']}
            onClick={() => router.push('/home')}
          />
        </Flex>
        <Stack spacing={6} w="full">
          <Box>
            <Skeleton isLoaded={!isLoading} alignSelf="start">
              {isValidated ? (
                <SuccessAlert>
                  {validationResult === ValidationResult.Success &&
                    t('Successfully validated')}
                  {validationResult === ValidationResult.Penalty &&
                    t('Validated')}
                </SuccessAlert>
              ) : (
                <ErrorAlert>{t('Validation failed')}</ErrorAlert>
              )}
            </Skeleton>
          </Box>
          <Box py={2} display={['none', 'block']}>
            <UserCard identity={{address, state}} />
          </Box>
          <Stack isInline={!isMobile} spacing={[4, 10]}>
            <ValidationReportBlockOverview>
              <Stack spacing={[6, 10]}>
                <Box>
                  <ValidationReportGauge>
                    <ValidationReportGaugeBox>
                      {isLoading ? (
                        <ValidationReportGaugeBar color={colors.gray['100']} />
                      ) : isValidated ? (
                        <ValidationReportGaugeBar
                          value={totalScore * 100}
                          color={
                            totalScore <= 0.75
                              ? colors.red['500']
                              : totalScore <= 0.9
                              ? colors.orange['500']
                              : colors.green['500']
                          }
                          bg="white"
                        />
                      ) : (
                        <ValidationReportGaugeBar
                          value={shortScore * 100 || 2}
                          color={colors.red['500']}
                          bg="white"
                        />
                      )}
                      <ValidationReportGaugeIcon
                        icon={<TimerIcon />}
                        display={['none', 'initial']}
                      />
                    </ValidationReportGaugeBox>
                    <ValidationReportGaugeStat>
                      <Skeleton isLoaded={!isLoading} w="auto">
                        {isValidated ? (
                          <ValidationReportGaugeStatValue>
                            {toPercent(totalScore)}
                          </ValidationReportGaugeStatValue>
                        ) : (
                          <ValidationReportGaugeStatValue color="red.500">
                            {t('Failed')}
                          </ValidationReportGaugeStatValue>
                        )}
                      </Skeleton>
                      <Skeleton isLoaded={!isLoading} w="auto">
                        <ValidationReportGaugeStatLabel>
                          {isValidated && t('Total score')}
                          {validationResult ===
                            ValidationResult.LateSubmission &&
                            t('Late submission')}
                          {validationResult ===
                            ValidationResult.MissedValidation &&
                            t('Missed validation')}
                          {validationResult === ValidationResult.WrongAnswers &&
                            t('Wrong answers')}
                        </ValidationReportGaugeStatLabel>
                      </Skeleton>
                    </ValidationReportGaugeStat>
                  </ValidationReportGauge>
                </Box>
                <Stack spacing={[2, 4]} isInline={!isMobile}>
                  <Flex justify="space-between">
                    <Skeleton isLoaded={!isLoading}>
                      <ValidationReportStat
                        label={t('Short session')}
                        value={
                          [
                            ValidationResult.MissedValidation,
                            ValidationResult.LateSubmission,
                          ].includes(validationResult)
                            ? '—'
                            : t('{{score}} ({{point}} out of {{flipsCount}})', {
                                score: toPercent(shortScore),
                                point: shortResults.point,
                                flipsCount: shortResults.flipsCount,
                              })
                        }
                      />
                    </Skeleton>
                  </Flex>
                  <Divider
                    orientation="horizontal"
                    display={['initial', 'none']}
                  />
                  <Flex justify="space-between">
                    <Skeleton isLoaded={!isLoading}>
                      <ValidationReportStat
                        label={t('Long session')}
                        value={
                          validationResult === ValidationResult.MissedValidation
                            ? '—'
                            : t('{{score}} ({{point}} out of {{flipsCount}})', {
                                score: toPercent(longScore),
                                point: longResults.point,
                                flipsCount: longResults.flipsCount,
                              })
                        }
                      />
                    </Skeleton>
                  </Flex>
                </Stack>
              </Stack>
            </ValidationReportBlockOverview>
            <ValidationReportBlockOverview>
              <Stack spacing={[6, 10]}>
                <Box>
                  <ValidationReportGauge>
                    <ValidationReportGaugeBox>
                      {isLoading ? (
                        <ValidationReportGaugeBar color={colors.gray['100']} />
                      ) : isValidated ? (
                        <ValidationReportGaugeBar
                          value={earningsScore * 100 || 2}
                          color={
                            // eslint-disable-next-line no-nested-ternary
                            earningsScore <= 0.5
                              ? colors.red['500']
                              : earningsScore <= 0.75
                              ? colors.orange['500']
                              : colors.green['500']
                          }
                          bg="white"
                        />
                      ) : (
                        <ValidationReportGaugeBar
                          value={2}
                          color={colors.red['500']}
                          bg="white"
                        />
                      )}
                      <ValidationReportGaugeIcon
                        icon={<SendOutIcon />}
                        display={['none', 'initial']}
                      />
                    </ValidationReportGaugeBox>
                    <ValidationReportGaugeStat>
                      <Skeleton isLoaded={!isLoading} w="auto">
                        {validationResult === ValidationResult.Success ? (
                          <ValidationReportGaugeStatValue>
                            {toDna(earnings)}
                          </ValidationReportGaugeStatValue>
                        ) : (
                          <ValidationReportGaugeStatValue color="red.500">
                            {toDna(totalMissedReward)}
                          </ValidationReportGaugeStatValue>
                        )}
                      </Skeleton>
                      <ValidationReportGaugeStatLabel>
                        {t('Earnings')}
                      </ValidationReportGaugeStatLabel>
                    </ValidationReportGaugeStat>
                  </ValidationReportGauge>
                </Box>

                <Flex justify="space-between" flexWrap="wrap">
                  <Flex mr={4} mb={[0, 4]}>
                    <Skeleton isLoaded={!isLoading}>
                      <ValidationReportStat
                        label={t('Missed invitation earnings')}
                        value={toDna(missedInvitationReward)}
                      />
                    </Skeleton>
                  </Flex>
                  <Divider
                    orientation="horizontal"
                    display={['initial', 'none']}
                    my={2}
                  />
                  <Flex mr={4} mb={[0, 4]}>
                    <Skeleton isLoaded={!isLoading}>
                      <ValidationReportStat
                        label={t('Missed reporting earnings')}
                        value={toDna(missedFlipReportReward)}
                      />
                    </Skeleton>
                  </Flex>
                  <Divider
                    orientation="horizontal"
                    display={['initial', 'none']}
                    my={2}
                  />
                  <Flex mr={4} mb={[0, 4]}>
                    <Skeleton isLoaded={!isLoading}>
                      <ValidationReportStat
                        label={t('Missed flip earnings')}
                        value={toDna(missedFlipReward)}
                      />
                    </Skeleton>
                  </Flex>
                </Flex>
              </Stack>
            </ValidationReportBlockOverview>
          </Stack>
          <Stack spacing={[0, 5]}>
            <Box mb={2}>
              <Heading color="brandGray.500" fontSize="lg" fontWeight={500}>
                {t('Earnings summary')}
              </Heading>
              <ExternalLink
                href={`https://scan.idena.io/identity/${address}/epoch/${
                  epoch?.epoch
                }/${isValidated ? 'rewards' : 'validation'}`}
              >
                {t('See the full report in blockchain explorer')}
              </ExternalLink>
            </Box>
            <Table fontWeight={500}>
              <Thead display={['none', 'table-header-group']}>
                <Tr>
                  <ValidationReportTh>
                    {t('Category')}
                    <ValidationReportThCorner borderLeftRadius="md" />
                  </ValidationReportTh>
                  <ValidationReportTh>
                    {t('Earned, iDNA')}
                    <ValidationReportThCorner />
                  </ValidationReportTh>
                  <ValidationReportTh>
                    {t('Missed, iDNA')}
                    <ValidationReportThCorner />
                  </ValidationReportTh>
                  <ValidationReportTh style={{width: '260px'}}>
                    {t('How to get maximum reward')}
                    <ValidationReportThCorner borderRightRadius="md" />
                  </ValidationReportTh>
                </Tr>
              </Thead>
              <Tbody>
                {stakingReward === 0 && candidateReward === 0 ? (
                  <>
                    <Tr>
                      <ValidationReportColumn>
                        <ValidationReportCategoryLabel
                          isFirst
                          label={t('Validation')}
                          description={
                            isMobile
                              ? t('Category')
                              : t('Rewards for the successfull validation')
                          }
                          info={t('Rewards for the successfull validation')}
                        />
                      </ValidationReportColumn>
                      <ValidationReportColumn>
                        <ValidationReportCategoryLabel
                          label={maybeDna(validationReward)}
                          description={isMobile ? t('Earned') : ''}
                        />
                      </ValidationReportColumn>
                      <ValidationReportColumn>
                        <ValidationReportCategoryLabel
                          label={
                            <Text
                              color={
                                missedValidationReward > 0 ? 'red.500' : ''
                              }
                            >
                              {maybeDna(missedValidationReward)}
                            </Text>
                          }
                          description={isMobile ? t('Missed') : ''}
                        />
                      </ValidationReportColumn>
                      <ValidationReportColumn display={['none', 'table-cell']}>
                        <TableValidationDesc
                          t={t}
                          validationResult={validationResult}
                          missedValidationReward={missedValidationReward}
                        />
                      </ValidationReportColumn>
                    </Tr>
                    <TableHiddenDescRow>
                      <TableValidationDesc
                        t={t}
                        validationResult={validationResult}
                        missedValidationReward={missedValidationReward}
                      />
                    </TableHiddenDescRow>
                  </>
                ) : (
                  <>
                    <Tr>
                      <ValidationReportColumn>
                        <ValidationReportCategoryLabel
                          isFirst
                          label={t('Staking')}
                          description={t('Quadratic staking rewards')}
                          info={t('Quadratic staking rewards')}
                        />
                      </ValidationReportColumn>
                      <ValidationReportColumn>
                        <ValidationReportCategoryLabel
                          label={maybeDna(stakingReward)}
                          description={isMobile ? t('Earned') : ''}
                        />
                      </ValidationReportColumn>
                      <ValidationReportColumn>
                        <ValidationReportCategoryLabel
                          label={
                            <Text
                              color={missedStakingReward > 0 ? 'red.500' : ''}
                            >
                              {maybeDna(missedStakingReward)}
                            </Text>
                          }
                          description={isMobile ? t('Missed') : ''}
                        />
                      </ValidationReportColumn>
                      <ValidationReportColumn display={['none', 'table-cell']}>
                        <TextLink href="/home?replenishStake">
                          {t('Add stake')}
                          <ChevronRightIcon />
                        </TextLink>
                      </ValidationReportColumn>
                    </Tr>
                    <TableHiddenDescRow>
                      <TextLink href="/home">
                        {t('Add stake')}
                        <ChevronRightIcon />
                      </TextLink>
                    </TableHiddenDescRow>
                    {state === IdentityStatus.Newbie &&
                      prevState === IdentityStatus.Candidate && (
                        <>
                          <Tr>
                            <ValidationReportColumn>
                              <ValidationReportCategoryLabel
                                isFirst
                                label={t('Validation')}
                                description={
                                  isMobile
                                    ? t('Category')
                                    : t(
                                        'Rewards for the 1st successful validation'
                                      )
                                }
                                info={t(
                                  'Rewards for the 1st successful validation'
                                )}
                              />
                            </ValidationReportColumn>
                            <ValidationReportColumn>
                              <ValidationReportCategoryLabel
                                label={maybeDna(candidateReward)}
                                description={isMobile ? t('Earned') : ''}
                              />
                            </ValidationReportColumn>
                            <ValidationReportColumn>
                              <ValidationReportCategoryLabel
                                label={
                                  <Text
                                    color={
                                      missedCandidateReward > 0 ? 'red.500' : ''
                                    }
                                  >
                                    {maybeDna(missedCandidateReward)}
                                  </Text>
                                }
                                description={isMobile ? t('Missed') : ''}
                              />
                            </ValidationReportColumn>
                            <ValidationReportColumn
                              display={['none', 'table-cell']}
                            >
                              <TableValidationDesc
                                t={t}
                                validationResult={validationResult}
                                missedValidationReward={missedCandidateReward}
                              />
                            </ValidationReportColumn>
                          </Tr>
                          <TableHiddenDescRow>
                            <TableValidationDesc
                              t={t}
                              validationResult={validationResult}
                              missedValidationReward={missedCandidateReward}
                            />
                          </TableHiddenDescRow>
                        </>
                      )}
                  </>
                )}
                <Tr>
                  <ValidationReportColumn>
                    <ValidationReportCategoryLabel
                      isFirst
                      label={t('Flips')}
                      description={
                        isMobile
                          ? t('Category')
                          : t('Rewards for submitted and qualified flips')
                      }
                      info={t('Rewards for submitted and qualified flips')}
                    />
                  </ValidationReportColumn>
                  <ValidationReportColumn>
                    <ValidationReportCategoryLabel
                      label={maybeDna(flipReward)}
                      description={isMobile ? t('Earned') : ''}
                    />
                  </ValidationReportColumn>
                  <ValidationReportColumn>
                    <ValidationReportCategoryLabel
                      label={
                        <Text color={missedFlipReward > 0 ? 'red.500' : ''}>
                          {maybeDna(missedFlipReward)}
                        </Text>
                      }
                      description={isMobile ? t('Missed') : ''}
                    />
                  </ValidationReportColumn>
                  <ValidationReportColumn display={['none', 'table-cell']}>
                    <TableFlipsDesc
                      t={t}
                      validationResult={validationResult}
                      missedFlipReward={missedFlipReward}
                      flipReward={flipReward}
                    />
                  </ValidationReportColumn>
                </Tr>
                <TableHiddenDescRow>
                  <TableFlipsDesc
                    t={t}
                    validationResult={validationResult}
                    missedFlipReward={missedFlipReward}
                    flipReward={flipReward}
                  />
                </TableHiddenDescRow>
                <Tr>
                  <ValidationReportColumn>
                    <ValidationReportCategoryLabel
                      isFirst
                      label={t('Invitations')}
                      description={
                        isMobile
                          ? t('Category')
                          : t('Rewards for invitee validation')
                      }
                      info={t('Rewards for invitee validation')}
                    />
                  </ValidationReportColumn>
                  <ValidationReportColumn>
                    <ValidationReportCategoryLabel
                      label={maybeDna(invitationReward)}
                      description={isMobile ? t('Earned') : ''}
                    />
                  </ValidationReportColumn>
                  <ValidationReportColumn>
                    <ValidationReportCategoryLabel
                      label={
                        <Text
                          color={missedInvitationReward > 0 ? 'red.500' : ''}
                        >
                          {maybeDna(missedInvitationReward)}
                        </Text>
                      }
                      description={isMobile ? t('Missed') : ''}
                    />
                  </ValidationReportColumn>
                  <ValidationReportColumn display={['none', 'table-cell']}>
                    <TableInvitationsDesc
                      t={t}
                      validationResult={validationResult}
                      missedInvitationReward={missedInvitationReward}
                      invitationReward={invitationReward}
                    />
                  </ValidationReportColumn>
                </Tr>
                <TableHiddenDescRow>
                  <TableInvitationsDesc
                    t={t}
                    validationResult={validationResult}
                    missedInvitationReward={missedInvitationReward}
                    invitationReward={invitationReward}
                  />
                </TableHiddenDescRow>
                <Tr>
                  <ValidationReportColumn>
                    <ValidationReportCategoryLabel
                      isFirst
                      label={t('Flip reports')}
                      description={
                        isMobile
                          ? t('Category')
                          : t('Rewards for reporting bad flips')
                      }
                      info={t('Rewards for reporting bad flips')}
                    />
                  </ValidationReportColumn>
                  <ValidationReportColumn>
                    <ValidationReportCategoryLabel
                      label={maybeDna(flipReportReward)}
                      description={isMobile ? t('Earned') : ''}
                    />
                  </ValidationReportColumn>
                  <ValidationReportColumn>
                    <ValidationReportCategoryLabel
                      label={
                        <Text
                          color={missedFlipReportReward > 0 ? 'red.500' : ''}
                        >
                          {maybeDna(missedFlipReportReward)}
                        </Text>
                      }
                      description={isMobile ? t('Missed') : ''}
                    />
                  </ValidationReportColumn>
                  <ValidationReportColumn display={['none', 'table-cell']}>
                    <TableFlipReportsDesc
                      t={t}
                      validationResult={validationResult}
                      missedFlipReportReward={missedFlipReportReward}
                      flipReportReward={flipReportReward}
                    />
                  </ValidationReportColumn>
                </Tr>
                <TableHiddenDescRow>
                  <TableFlipReportsDesc
                    t={t}
                    validationResult={validationResult}
                    missedFlipReportReward={missedFlipReportReward}
                    flipReportReward={flipReportReward}
                  />
                </TableHiddenDescRow>
              </Tbody>
            </Table>
          </Stack>
        </Stack>
      </Page>
    </Layout>
  )
}
Example #20
Source File: Membership.js    From web-client with Apache License 2.0 4 votes vote down vote up
ProjectMembership = () => {
    const { projectId } = useParams();
    const [users] = useFetch(`/users`)
    const [members, updateMembers] = useFetch(`/projects/${projectId}/users`)
    const [savedProject] = useFetch(`/projects/${projectId}`);
    const [availableUsers, setAvailableUsers] = useState([]);

    const handleOnClick = ev => {
        ev.preventDefault();

        const userId = document.getElementById('userId').value;
        const userData = { userId: userId };
        secureApiFetch(`/projects/${projectId}/users`, {
            method: 'POST',
            body: JSON.stringify(userData)
        }).then(() => {
            updateMembers()
        })
    }

    const handleDelete = (member) => {
        secureApiFetch(`/projects/${projectId}/users/${member.membership_id}`, {
            method: 'DELETE'
        }).then(() => {
            updateMembers()
        })
    }

    useEffect(() => {
        if (members && users && users.length > 0) {
            const memberIds = members.reduce((list, user) => [...list, user.id], []);
            setAvailableUsers(users.filter(user => !memberIds.includes(user.id)));
        }
    }, [members, users]);

    return <div>
        <PageTitle value="Project membership" />
        <div className="heading">
            <Breadcrumb>
                <Link to="/projects">Projects</Link>
                {savedProject && <Link to={`/projects/${savedProject.id}`}>{savedProject.name}</Link>}
            </Breadcrumb>
        </div>

        <Title title='Members' />

        {availableUsers.length > 0 ?
            <form>
                <label>
                    Select user
                    <Select id="userId">
                        {availableUsers && availableUsers.map((user, index) =>
                            <option key={index} value={user.id}>{user.full_name}</option>
                        )}
                    </Select>
                </label>
                <PrimaryButton onClick={handleOnClick} leftIcon={<IconPlus />}>Add as member</PrimaryButton>
            </form> :
            <Alert status="info">
                <AlertIcon />
                All users have been added to the project.
            </Alert>
        }

        <Table>
            <Thead>
                <Tr>
                    <Th style={{ width: '80px' }}>&nbsp;</Th>
                    <Th>Name</Th>
                    <Th>Role</Th>
                    <Th>&nbsp;</Th>
                </Tr>
            </Thead>
            <Tbody>
                {null === members &&
                    <LoadingTableRow numColumns={4} />}
                {null !== members && 0 === members.length &&
                    <NoResultsTableRow numColumns={4} />}
                {members && members.map((member, index) =>
                    <Tr key={index}>
                        <Td><UserAvatar email={member.email} /></Td>
                        <Td><UserLink userId={member.id}>{member.full_name}</UserLink></Td>
                        <Td><UserRoleBadge role={member.role} /></Td>
                        <Td textAlign="right">
                            <DeleteIconButton onClick={() => handleDelete(member)} />
                        </Td>
                    </Tr>
                )
                }
            </Tbody>
        </Table>
    </div>
}
Example #21
Source File: components.js    From idena-web with MIT License 4 votes vote down vote up
export function WalletTransactions({address}) {
  const LIMIT = 10
  const {t, i18n} = useTranslation()

  const toNumber = toLocaleNumber(i18n.language, {maximumFractionDigits: 4})

  const fetchTxs = ({pageParam = null}) =>
    getTxs(address, LIMIT, pageParam).then(result => {
      if (!result) {
        return {result: []}
      }
      const newResult = result.map(tx => {
        const fromWallet =
          lowerCase(address) === lowerCase(tx.from) ? address : null
        const toWallet =
          lowerCase(address) === lowerCase(tx.to) ? address : null

        const direction = fromWallet ? t('Sent') : t('Received')

        const typeName = tx.type === 'SendTx' ? direction : transactionType(tx)

        const sourceWallet = fromWallet || toWallet
        const signAmount = fromWallet ? -tx.amount : `+${tx.amount}`
        const counterParty = fromWallet ? tx.to : tx.from
        const counterPartyWallet = fromWallet ? toWallet : fromWallet
        const isMining = !tx.timestamp

        const nextTx = {
          ...tx,
          typeName,
          wallet: sourceWallet,
          direction,
          signAmount,
          counterParty,
          counterPartyWallet,
          isMining,
        }
        return nextTx
      })
      return {result: newResult, continuationToken: result.continuationToken}
    })

  const {
    data,
    fetchNextPage,
    hasNextPage,
    isFetchingNextPage,
    status,
  } = useInfiniteQuery(['transactions', address], fetchTxs, {
    getNextPageParam: lastPage => lastPage?.continuationToken,
    refetchInterval: 10 * 1000,
  })

  const isLoading = status === 'loading'

  return (
    <div>
      <Table
        sx={{
          '&': {
            tableLayout: 'fixed',
          },
          tr: {
            '&:last-of-type': {
              td: {borderBottomWidth: 0},
            },
          },
        }}
      >
        <Thead display={['none', 'table-header-group']}>
          <Tr>
            <RoundedTh isLeft>{t('Transaction')}</RoundedTh>
            <RoundedTh>{t('Address')}</RoundedTh>
            <RoundedTh textAlign="right">{t('Amount, iDNA')}</RoundedTh>
            <RoundedTh textAlign="right">{t('Fee, iDNA')}</RoundedTh>
            <RoundedTh>{t('Date')}</RoundedTh>
            <RoundedTh isRight>{t('Blockchain transaction ID')}</RoundedTh>
          </Tr>
        </Thead>
        <Tbody>
          {!isLoading &&
            data &&
            data.pages.map((group, i) => (
              <React.Fragment key={i}>
                {group.result.map((tx, k) => (
                  <Tr key={i + k}>
                    <TransactionsTd>
                      <RowStatus
                        isMining={tx.isMining}
                        direction={tx.direction}
                        type={tx.typeName}
                        walletName="Main"
                        tx={tx}
                      />
                    </TransactionsTd>

                    <TransactionsTd display={['none', 'table-cell']}>
                      {(!tx.to && '\u2013') || (
                        <Flex align="center">
                          <Avatar
                            address={lowerCase(tx.counterParty)}
                            size={8}
                          />
                          <Box ml={3}>
                            <div>
                              {tx.direction === 'Sent' ? t('To') : t('From')}{' '}
                              {tx.counterPartyWallet
                                ? `${t('wallet')} Main`
                                : t('address')}
                            </div>
                            <TableHint>
                              <Text isTruncated w="130px">
                                {tx.counterParty}
                              </Text>
                            </TableHint>
                          </Box>
                        </Flex>
                      )}
                    </TransactionsTd>

                    <TransactionsTd
                      display={['none', 'table-cell']}
                      textAlign="right"
                    >
                      <Box color={tx.signAmount < 0 ? 'red.500' : 'gray.500'}>
                        {(tx.type === 'kill' && t('See in Explorer...')) ||
                          (tx.amount === '0'
                            ? '\u2013'
                            : toNumber(tx.signAmount))}
                      </Box>
                    </TransactionsTd>

                    <TransactionsTd
                      display={['none', 'table-cell']}
                      textAlign="right"
                    >
                      {(!tx.isMining &&
                        (tx.fee === '0' ? '\u2013' : toNumber(tx.fee))) || (
                        <div>
                          <div> {tx.maxFee} </div>
                          <TableHint>{t('Fee limit')}</TableHint>
                        </div>
                      )}
                    </TransactionsTd>
                    <TransactionsTd display={['none', 'table-cell']}>
                      {!tx.timestamp
                        ? '\u2013'
                        : new Date(tx.timestamp).toLocaleString()}
                    </TransactionsTd>

                    <TransactionsTd display={['none', 'table-cell']}>
                      <div>
                        <div>
                          {tx.isMining ? t('Mining...') : t('Confirmed')}
                        </div>
                        <TableHint>
                          <Text isTruncated w="130px">
                            {tx.hash}
                          </Text>
                        </TableHint>
                      </div>
                    </TransactionsTd>
                  </Tr>
                ))}
              </React.Fragment>
            ))}
        </Tbody>
      </Table>
      {isLoading && (
        <Stack spacing={2} mt={2}>
          {new Array(10).fill(0).map((_, i) => (
            <Skeleton key={i} height={10} w="full"></Skeleton>
          ))}
        </Stack>
      )}
      {!isLoading && hasNextPage && (
        <Flex justify="center" mt={2}>
          <FlatButton
            mb={2.5}
            onClick={() => fetchNextPage()}
            disabled={isFetchingNextPage}
          >
            {isFetchingNextPage ? t('Loading more...') : t('Load More')}
          </FlatButton>
        </Flex>
      )}

      {!isLoading && data?.pages && data.pages[0].result?.length === 0 && (
        <Box color="muted" textAlign="center" lineHeight="40vh">
          {t(`You don't have any transactions yet`)}
        </Box>
      )}
    </div>
  )
}
Example #22
Source File: ChallengeReviewRow.jsx    From scaffold-directory with MIT License 4 votes vote down vote up
export default function ChallengeReviewRow({ challenge, isLoading, approveClick, rejectClick, userProvider }) {
  const [comment, setComment] = useState(challenge.reviewComment ?? "");
  const [testPassed, setTestPassed] = useState(null);
  const [isRunningTests, setIsRunningTests] = useState(false);
  const { isOpen, onOpen, onClose } = useDisclosure();
  const address = useUserAddress(userProvider);

  if (!challengeInfo[challenge.id]) {
    return null;
  }

  // We asume that rejected challenges will always have review Comments.
  const isAutograded = challenge.autograding;
  // ToDo. Use the stored events.
  const isResubmitted = !isAutograded && !!challenge.reviewComment;

  const runTests = async () => {
    try {
      console.log("Testing challenge with the auto-grader");

      setIsRunningTests(true);
      setTestPassed(null);

      const result = await runAutograderTest(challenge.id, challenge.contractUrl, address);
      const resultData = result.data;

      console.log("Testing results", resultData);
      setTestPassed(resultData.success);
      setComment(resultData.feedback ?? resultData.error);
    } catch (e) {
      console.log("Error calling the auto-grader", e);
    } finally {
      setIsRunningTests(false);
    }
  };

  const challengeReviewDisplay = (
    <Link as={RouteLink} to={`/challenge/${challenge.id}`}>
      {challengeInfo[challenge.id].label}
      {isResubmitted && (
        <>
          <br />
          <Text fontSize="xs">(Resubmitted)</Text>
        </>
      )}
      {isAutograded && (
        <>
          <br />
          <Text fontSize="xs" color="orange.500">
            (Autograded)
          </Text>
        </>
      )}
    </Link>
  );

  const submittedMoment = moment(challenge.submittedTimestamp);

  const reviewRow = (
    <>
      <Td>
        <Link as={RouteLink} to={`/builders/${challenge.userAddress}`} pos="relative">
          <Address address={challenge.userAddress} w="12.5" fontSize="16" />
        </Link>
      </Td>
      <Td>{challengeReviewDisplay}</Td>
      <Td>
        <DateWithTooltip timestamp={challenge.submittedTimestamp} />
      </Td>
    </>
  );

  return (
    <Tr>
      {reviewRow}
      <Td>
        <Button type="button" colorScheme="blue" disabled={isLoading} className="danger" onClick={onOpen} size="xs">
          Review
        </Button>
      </Td>
      <Modal isOpen={isOpen} onClose={onClose} size="xl">
        <ModalOverlay />
        <ModalContent maxW="56rem">
          <ModalHeader>Review Challenge</ModalHeader>
          <ModalCloseButton />
          <Table mb={4}>
            <Thead>
              <Tr>
                <Th>Builder</Th>
                <Th>Challenge & Links</Th>
              </Tr>
            </Thead>
            <Tbody>
              <Tr>
                <Td>
                  <Link as={RouteLink} to={`/builders/${challenge.userAddress}`} pos="relative">
                    <Address address={challenge.userAddress} w="12.5" fontSize="16" />
                  </Link>
                </Td>
                <Td>
                  {challengeReviewDisplay}
                  <UnorderedList>
                    <ListItem>
                      <Link
                        // Legacy branchUrl
                        href={challenge.contractUrl || challenge.branchUrl}
                        color="teal.500"
                        target="_blank"
                        rel="noopener noreferrer"
                      >
                        Contract
                      </Link>
                    </ListItem>
                    <ListItem>
                      <Link href={challenge.deployedUrl} color="teal.500" target="_blank" rel="noopener noreferrer">
                        Demo
                      </Link>
                    </ListItem>
                    <ListItem>
                      Submitted{" "}
                      <Tooltip label={submittedMoment.format("YYYY-MM-DD, HH:mm")}>
                        <chakra.span cursor="pointer">{submittedMoment.fromNow()}</chakra.span>
                      </Tooltip>
                    </ListItem>
                    <ListItem listStyleType="none" mt={2}>
                      <Flex align="center">
                        <Button onClick={runTests} isLoading={isRunningTests} mr={2}>
                          Run tests
                        </Button>
                        {isBoolean(testPassed) && (
                          <Badge colorScheme={testPassed ? "green" : "red"}>
                            {testPassed ? "Accepted" : "Rejected"}
                          </Badge>
                        )}
                      </Flex>
                    </ListItem>
                  </UnorderedList>
                </Td>
              </Tr>
            </Tbody>
          </Table>
          <ModalBody px={6} pb={0}>
            <Tabs variant="enclosed-colored">
              <TabList>
                <Tab>Write</Tab>
                <Tab>Preview</Tab>
              </TabList>
              <TabPanels align="left">
                <TabPanel p={0}>
                  <Textarea
                    onChange={e => {
                      const value = e.target.value;
                      setComment(value);
                    }}
                    placeholder="Comment"
                    style={{ marginBottom: 10 }}
                    rows={10}
                    value={comment}
                    borderTopRadius={0}
                  />
                </TabPanel>
                <TabPanel>
                  <ReactMarkdown components={ChakraUIRenderer(chakraMarkdownComponents)}>{comment}</ReactMarkdown>
                </TabPanel>
              </TabPanels>
            </Tabs>
          </ModalBody>
          <ModalFooter>
            <Button
              type="button"
              colorScheme="red"
              disabled={isLoading}
              className="danger"
              onClick={() => rejectClick(challenge.userAddress, challenge.id, comment)}
              size="sm"
              isFullWidth
            >
              Reject
            </Button>
            <Button
              type="button"
              colorScheme="green"
              disabled={isLoading}
              ml={3}
              onClick={() => approveClick(challenge.userAddress, challenge.id, comment)}
              size="sm"
              isFullWidth
            >
              Approve
            </Button>
          </ModalFooter>
        </ModalContent>
      </Modal>
    </Tr>
  );
}
Example #23
Source File: Outputs.js    From web-client with Apache License 2.0 4 votes vote down vote up
CommandOutputs = ({ command }) => {
    const [commandOutputs, updateCommandOutputs] = useFetch(`/attachments?parentType=command&parentId=${command.id}`)
    const [modalVisible, setModalVisible] = useState(false);
    const [content, setContent] = useState(null);

    const onDeleteOutputClick = (ev, attachmentId) => {
        ev.preventDefault();

        secureApiFetch(`/attachments/${attachmentId}`, { method: 'DELETE' })
            .then(() => {
                actionCompletedToast("The output has been deleted.");
                updateCommandOutputs();
            })
            .catch(err => console.error(err))
    }

    const onDownloadClick = (ev, attachmentId) => {
        secureApiFetch(`/attachments/${attachmentId}`, { method: 'GET', headers: {} })
            .then(resp => {
                const contentDispositionHeader = resp.headers.get('Content-Disposition');
                const filenameRe = new RegExp(/filename="(.*)";/)
                const filename = filenameRe.exec(contentDispositionHeader)[1]
                return Promise.all([resp.blob(), filename]);
            })
            .then((values) => {
                const blob = values[0];
                const filename = values[1];
                const url = URL.createObjectURL(blob);
                const a = document.createElement('a');
                a.href = url;
                a.download = filename;
                a.click();
            })
    }

    const onViewClick = (ev, attachmentId) => {
        secureApiFetch(`/attachments/${attachmentId}`, { method: 'GET', headers: {} })
            .then(resp => {
                const contentDispositionHeader = resp.headers.get('Content-Disposition');
                const filenameRe = new RegExp(/filename="(.*)";/)
                const filename = filenameRe.exec(contentDispositionHeader)[1]
                return Promise.all([resp.blob(), filename]);
            })
            .then(async (values) => {
                const blob = values[0];
                setContent(await blob.text());
                setModalVisible(true);
            })
    }

    const onModalClose = () => {
        setModalVisible(false);
    }

    return <>
        <ModalDialog visible={modalVisible} title="Preview output" onModalClose={onModalClose} style={{ width: '80%', height: '80%', maxHeight: '80%' }}>
            <Textarea style={{ width: '100%', height: '90%' }} defaultValue={content} readOnly>
            </Textarea>
        </ModalDialog>

        <RestrictedComponent roles={['administrator', 'superuser', 'user']}>
            <AttachmentsDropzone parentType={"command"} parentId={command.id} onUploadFinished={updateCommandOutputs} />
        </RestrictedComponent>

        <h4>
            Command output list
        </h4>

        <Table>
            <Thead>
                <Tr>
                    <Th>Filename</Th>
                    <Th>Mimetype</Th>
                    <Th>File size</Th>
                    <Th>Upload date</Th>
                    <Th>Uploaded by</Th>
                    <Th>&nbsp;</Th>
                </Tr>
            </Thead>
            <Tbody>
                {null === commandOutputs && <LoadingTableRow numColumns={6} />}
                {null !== commandOutputs && commandOutputs.length === 0 && <NoResultsTableRow numColumns={6} />}
                {null !== commandOutputs && commandOutputs.length !== 0 && commandOutputs.map((commandOutput, index) =>
                    <Tr key={index}>
                        <Td>{commandOutput.client_file_name}</Td>
                        <Td>{commandOutput.file_mimetype}</Td>
                        <Td><FileSizeSpan fileSize={commandOutput.file_size} /></Td>
                        <Td><RelativeDateFormatter date={commandOutput.insert_ts} /></Td>
                        <Td><UserLink userId={commandOutput.submitter_uid}>{commandOutput.submitter_name}</UserLink></Td>
                        <Td textAlign="right">
                            <ButtonGroup isAttached>
                                <SecondaryButton onClick={ev => onViewClick(ev, commandOutput.id)}>View</SecondaryButton>
                                <SecondaryButton onClick={ev => onDownloadClick(ev, commandOutput.id)}>Download</SecondaryButton>
                                <DeleteIconButton onClick={ev => onDeleteOutputClick(ev, commandOutput.id)} />
                            </ButtonGroup>
                        </Td>
                    </Tr>
                )}
            </Tbody>
        </Table>
    </>
}
Example #24
Source File: ActivityPage.js    From DAOInsure with MIT License 4 votes vote down vote up
function ActivityPage() {
	const [data, setData] = useState();

	const [loadingData, setLoadingData] = useState();
	useEffect(() => {
		async function init() {
			setLoadingData(true);
			// querying superfluid subgraph to create pie diagram of flow towards DAO Contract
			const response = await axios.post(
				"https://api.thegraph.com/subgraphs/name/superfluid-finance/superfluid-mumbai",
				{
					query: `
                    {
                        flows(where:{ recipient: "0xb77963bfd55f5246068c09a2048fa3ab310e4a17" }) {
                        id
                        flowRate
                        lastUpdate
                            owner {
                                id
                            }
                        }
                    }
                `,
				}
			);

			let datas = [];

			response.data.data.flows.map((flow) => {
				let secondsElapsed =
					Math.floor(Date.now() / 1000) - parseInt(flow.lastUpdate);
				let outFlowed = web3.utils.fromWei(
					web3.utils
						.toBN(flow.flowRate)
						.mul(web3.utils.toBN(secondsElapsed))
						.toString(),
					"ether"
				);
				let obj = {
					id: flow.owner.id,
					label: flow.owner.id,
					value: outFlowed,
					flowRate: web3.utils.toBN(flow.flowRate),
					sumInWei: web3.utils
						.toBN(flow.flowRate)
						.mul(web3.utils.toBN(secondsElapsed)),
				};
				datas.push(obj);
			});
			setData(datas);
			setLoadingData(false);
		}
		init();
	}, [data]);

	useEffect(() => {
		if (data != undefined) {
			setTimeout(() => {
				for (let i = 0; i < data.length; i++) {
					data[i].value = web3.utils
						.fromWei(data[i].sumInWei.add(data[i].flowRate))
						.toString();
					data[i].sumInWei = data[i].sumInWei.add(data[i].flowRate);
				}
				setData(data);
			}, 1000);
		}
	}, [data]);

	return (
		<Grid px='250px' gridGap='10px' py='20px'>
			<Heading fontSize='24px' color='whatsapp.500'>
				Members
			</Heading>
			<Box height='400px'>
				{loadingData ? <Spinner /> : <MyResponsivePie data={data} />}
			</Box>
			<Table>
				<Thead>
					<Tr>
						<Th>Address</Th>
						<Th>outFlowed</Th>
					</Tr>
				</Thead>
				<Tbody>
					{data == undefined ? (
						<Spinner />
					) : (
						<>
							{data.map((data, index) => {
								return (
									<Tr>
										<Td>
											<GreenTag>{data.id}</GreenTag>
										</Td>
										<Td>{data.value}</Td>
									</Tr>
								);
							})}
						</>
					)}
				</Tbody>
			</Table>
		</Grid>
	);
}
Example #25
Source File: AttachmentsTable.js    From web-client with Apache License 2.0 4 votes vote down vote up
AttachmentsTable = ({ attachments, reloadAttachments }) => {

    const [modalVisible, setModalVisible] = useState(false);
    const [content, setContent] = useState(null);

    const onModalClose = () => {
        setModalVisible(false);
    }

    const deleteAttachmentById = useDelete('/attachments/', reloadAttachments);

    const onViewClick = (ev, attachmentId) => {
        secureApiFetch(`/attachments/${attachmentId}`, { method: 'GET', headers: {} })
            .then(resp => {
                const contentDispositionHeader = resp.headers.get('Content-Disposition');
                const contentType = resp.headers.get('Content-Type');
                const filenameRe = new RegExp(/filename="(.*)";/)
                const filename = filenameRe.exec(contentDispositionHeader)[1]
                return Promise.all([contentType, filename, resp.blob()]);
            })
            .then(async (values) => {
                const [contentType, , blob] = values;

                if (contentType.indexOf('image/') !== -1) {
                    setContent(<img src={await URL.createObjectURL(blob)} alt="" />);
                    // @todo -> URL.revokeObjectURL
                } else {
                    setContent(<textarea style={{ width: '100%', height: '90%' }} value={await blob.text()} readOnly />);
                }
                setModalVisible(true);
            })
    }

    const onDownloadClick = (ev, attachmentId) => {
        secureApiFetch(`/attachments/${attachmentId}`, { method: 'GET', headers: {} })
            .then(resp => {
                const contentDispositionHeader = resp.headers.get('Content-Disposition');
                const filenameRe = new RegExp(/filename="(.*)";/)
                const filename = filenameRe.exec(contentDispositionHeader)[1]
                return Promise.all([resp.blob(), filename]);
            })
            .then((values) => {
                const blob = values[0];
                const filename = values[1];
                const url = URL.createObjectURL(blob);
                const a = document.createElement('a');
                a.href = url;
                a.download = filename;
                a.click();
            })
    }

    const onDeleteAttachmentClick = (ev, attachmentId) => {
        deleteAttachmentById(attachmentId)
            .then(() => reloadAttachments());
    }

    const safeResolveMime = mimeType => {
        try {
            return resolveMime(mimeType)['name']
        } catch (err) {
            console.error(err);
            return mimeType;
        }
    }

    if (!attachments) {
        return <Loading />
    }

    return <>
        <ModalDialog visible={modalVisible} title="Preview output" onModalClose={onModalClose} style={{ overflow: 'auto', width: '80%', height: '80%', maxHeight: '80%' }}>
            {content}
        </ModalDialog>

        <Table>
            <Thead>
                <Tr>
                    <Th>Filename</Th>
                    <Th>Mimetype</Th>
                    <Th>File size</Th>
                    <Th>Upload date</Th>
                    <Th>Uploaded by</Th>
                    <Th>&nbsp;</Th>
                </Tr>
            </Thead>
            <Tbody>
                {attachments.length === 0 && <NoResultsTableRow numColumns={6} />}
                {attachments.map((attachment, index) =>
                    <Tr key={index}>
                        <Td>{attachment.client_file_name}</Td>
                        <Td><span title={safeResolveMime(attachment.file_mimetype)}>{attachment.file_mimetype}</span></Td>
                        <Td><FileSizeSpan fileSize={attachment.file_size} /></Td>
                        <Td><RelativeDateFormatter date={attachment.insert_ts} /></Td>
                        <Td><UserLink userId={attachment.submitter_uid}>{attachment.submitter_name}</UserLink></Td>
                        <Td style={{ display: "flex" }}>
                            <SecondaryButton onClick={ev => onViewClick(ev, attachment.id)}>View</SecondaryButton>
                            <SecondaryButton onClick={ev => onDownloadClick(ev, attachment.id)}>Download</SecondaryButton>
                            <DeleteIconButton onClick={ev => onDeleteAttachmentClick(ev, attachment.id)} />
                        </Td>
                    </Tr>
                )}
            </Tbody>
        </Table>
    </>
}
Example #26
Source File: SubmissionReviewView.jsx    From scaffold-directory with MIT License 4 votes vote down vote up
export default function SubmissionReviewView({ userProvider }) {
  const address = useUserAddress(userProvider);
  const [challenges, setChallenges] = React.useState([]);
  const [isLoadingChallenges, setIsLoadingChallenges] = React.useState(true);
  const [draftBuilds, setDraftBuilds] = React.useState([]);
  const [isLoadingDraftBuilds, setIsLoadingDraftBuilds] = React.useState(true);
  const toast = useToast({ position: "top", isClosable: true });
  const toastVariant = useColorModeValue("subtle", "solid");
  const { secondaryFontColor } = useCustomColorModes();

  const fetchSubmittedChallenges = useCallback(async () => {
    setIsLoadingChallenges(true);
    let fetchedChallenges;
    try {
      fetchedChallenges = await getSubmittedChallenges(address);
    } catch (error) {
      toast({
        description: "There was an error getting the submitted challenges. Please try again",
        status: "error",
        variant: toastVariant,
      });
      setIsLoadingChallenges(false);
      return;
    }
    setChallenges(fetchedChallenges.sort(bySubmittedTimestamp));
    setIsLoadingChallenges(false);
  }, [address, toastVariant, toast]);

  const fetchSubmittedBuilds = useCallback(async () => {
    setIsLoadingDraftBuilds(true);
    let fetchedDraftBuilds;
    try {
      fetchedDraftBuilds = await getDraftBuilds(address);
    } catch (error) {
      toast({
        description: "There was an error getting the draft builds. Please try again",
        status: "error",
        variant: toastVariant,
      });
      setIsLoadingDraftBuilds(false);
      return;
    }
    setDraftBuilds(fetchedDraftBuilds.sort(bySubmittedTimestamp));
    setIsLoadingDraftBuilds(false);
  }, [address, toastVariant, toast]);

  useEffect(() => {
    if (!address) {
      return;
    }
    fetchSubmittedChallenges();
    // eslint-disable-next-line
  }, [address]);

  useEffect(() => {
    if (!address) {
      return;
    }
    fetchSubmittedBuilds();
    // eslint-disable-next-line
  }, [address]);

  const handleSendChallengeReview = reviewType => async (userAddress, challengeId, comment) => {
    let signMessage;
    try {
      signMessage = await getChallengeReviewSignMessage(address, userAddress, challengeId, reviewType);
    } catch (error) {
      toast({
        description: " Sorry, the server is overloaded. ???",
        status: "error",
        variant: toastVariant,
      });
      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,
      });
      console.error(error);
      return;
    }

    try {
      await patchChallengeReview(address, signature, { userAddress, challengeId, newStatus: reviewType, comment });
    } catch (error) {
      if (error.status === 401) {
        toast({
          status: "error",
          description: "Submission Error. You don't have the required role.",
          variant: toastVariant,
        });
        return;
      }
      toast({
        status: "error",
        description: "Submission Error. Please try again.",
        variant: toastVariant,
      });
      return;
    }
    toast({
      description: "Review submitted successfully",
      status: "success",
      variant: toastVariant,
    });
    fetchSubmittedChallenges();
  };

  const handleSendBuildReview = reviewType => async (userAddress, buildId) => {
    let signMessage;
    try {
      signMessage = await getBuildReviewSignMessage(address, buildId, reviewType);
    } catch (error) {
      toast({
        description: " Sorry, the server is overloaded. ???",
        status: "error",
        variant: toastVariant,
      });
      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,
      });
      return;
    }

    try {
      await patchBuildReview(address, signature, { userAddress, buildId, newStatus: reviewType });
    } catch (error) {
      if (error.status === 401) {
        toast({
          status: "error",
          description: "Submission Error. You don't have the required role.",
          variant: toastVariant,
        });
        return;
      }
      toast({
        status: "error",
        description: "Submission Error. Please try again.",
        variant: toastVariant,
      });
      return;
    }

    toast({
      description: "Review submitted successfully",
      status: "success",
      variant: toastVariant,
    });
    fetchSubmittedBuilds();
  };

  return (
    <Container maxW="container.lg">
      <Container maxW="container.md" centerContent>
        <Heading as="h1">Review Submissions</Heading>
        <Text color={secondaryFontColor}>Pending submissions to validate.</Text>
        <Text color={secondaryFontColor} mb="6">
          Check our{" "}
          <Link href={RUBRIC_URL} color="teal.500" isExternal>
            Grading Rubric
          </Link>
          .
        </Text>
      </Container>
      <Heading as="h2" size="lg" mt={6} mb={4}>
        Challenges
      </Heading>
      <Box overflowX="auto">
        {isLoadingChallenges ? (
          <ChallengesTableSkeleton />
        ) : (
          <Table>
            <Thead>
              <Tr>
                <Th>Builder</Th>
                <Th>Challenge</Th>
                <Th>Submitted time</Th>
                <Th>Actions</Th>
              </Tr>
            </Thead>
            <Tbody>
              {!challenges || challenges.length === 0 ? (
                <Tr>
                  <Td colSpan={6}>
                    <Text color={secondaryFontColor} textAlign="center" mb={4}>
                      <Icon as={HeroIconInbox} w={6} h={6} color={secondaryFontColor} mt={6} mb={4} />
                      <br />
                      All challenges have been reviewed
                    </Text>
                  </Td>
                </Tr>
              ) : (
                challenges.map(challenge => (
                  <ChallengeReviewRow
                    key={`${challenge.userAddress}_${challenge.id}`}
                    challenge={challenge}
                    isLoading={isLoadingChallenges}
                    approveClick={handleSendChallengeReview("ACCEPTED")}
                    rejectClick={handleSendChallengeReview("REJECTED")}
                    userProvider={userProvider}
                  />
                ))
              )}
            </Tbody>
          </Table>
        )}
      </Box>
      <Heading as="h2" size="lg" mt={6} mb={4}>
        Builds
      </Heading>
      <Box overflowX="auto">
        {isLoadingDraftBuilds ? (
          <BuildsTableSkeleton />
        ) : (
          <Table mb={4}>
            <Thead>
              <Tr>
                <Th>Builder</Th>
                <Th>Build Name</Th>
                <Th>Description</Th>
                <Th>Branch URL</Th>
                <Th>Submitted time</Th>
                <Th>Actions</Th>
              </Tr>
            </Thead>
            <Tbody>
              {!draftBuilds || draftBuilds.length === 0 ? (
                <Tr>
                  <Td colSpan={5}>
                    <Text color={secondaryFontColor} textAlign="center" mb={4}>
                      <Icon as={HeroIconInbox} w={6} h={6} color={secondaryFontColor} mt={6} mb={4} />
                      <br />
                      All builds have been reviewed
                    </Text>
                  </Td>
                </Tr>
              ) : (
                draftBuilds.map(build => (
                  <BuildReviewRow
                    key={`${build.userAddress}_${build.id}`}
                    build={build}
                    isLoading={isLoadingDraftBuilds}
                    approveClick={handleSendBuildReview("ACCEPTED")}
                    rejectClick={handleSendBuildReview("REJECTED")}
                  />
                ))
              )}
            </Tbody>
          </Table>
        )}
      </Box>
    </Container>
  );
}