@chakra-ui/react#ListItem JavaScript Examples

The following examples show how to use @chakra-ui/react#ListItem. 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: affiliate.js    From idena-web with MIT License 6 votes vote down vote up
function UniversalListItem({title, isLast, children, ...props}) {
  const orientation = useBreakpointValue(['horizontal', 'vertical'])
  return (
    <ListItem listStyleType={['none', 'disc']} fontSize="base" {...props}>
      <Box
        position="relative"
        fontSize={['base', 'md']}
        fontWeight={[500, 400]}
        textColor="muted"
      >
        <Text
          fontSize={['base', 'mdx']}
          fontWeight={500}
          color="gray.500"
          pt={0.5}
          my={1}
        >
          {title}
        </Text>
        {children}
        <Divider
          display={isLast ? 'none' : 'block'}
          position={['initial', 'absolute']}
          top="15px"
          left="-15px"
          mt={[6, 0]}
          borderColor="brandGray.800"
          orientation={orientation}
          zIndex={-1}
        />
        <Box h={4} w={4} />
      </Box>
    </ListItem>
  )
}
Example #2
Source File: components.js    From idena-web with MIT License 6 votes vote down vote up
function IdenaBotFeatureList({features, listSeparator = ';'}) {
  return (
    <UnorderedList spacing={1} styleType="'- '" pl="2.5">
      {features.map((feature, idx) => (
        <ListItem key={feature} textTransform="lowercase">
          {feature}
          {idx < features.length - 1 ? listSeparator : '.'}
        </ListItem>
      ))}
    </UnorderedList>
  )
}
Example #3
Source File: components.js    From idena-web with MIT License 6 votes vote down vote up
function BadFlipListItem({
  flipCase,
  description,
  isActive,
  children,
  ...props
}) {
  return (
    <ListItem
      display={[isActive ? 'list-item' : 'none', 'list-item']}
      name={`badFlip${flipCase}`}
      py={2}
      cursor="pointer"
      {...props}
    >
      <Stack isInline spacing={[0, 2]}>
        <BadFlipListItemCircle
          display={['none', 'flex']}
          bg={isActive ? 'red.500' : 'red.012'}
          color={isActive ? 'white' : 'red.500'}
        >
          {flipCase + 1}
        </BadFlipListItemCircle>
        <Stack spacing={1}>
          <Text fontSize={['lg', 'md']} fontWeight={['500', 'normal']}>
            {children}
          </Text>
          {isActive && description && (
            <Text color="muted" fontSize={['mdx', '12px']}>
              {description}
            </Text>
          )}
        </Stack>
      </Stack>
    </ListItem>
  )
}
Example #4
Source File: sidebar.js    From idena-web with MIT License 6 votes vote down vote up
// eslint-disable-next-line react/prop-types
function NavItem({href, baseHref, icon, text, onClick, badge}) {
  const router = useRouter()
  const active = href && router.pathname.startsWith(baseHref || href)
  return (
    <ListItem>
      <NextLink href={href}>
        <ChakraLink
          transition="background 0.3s ease"
          width="100%"
          height="100%"
          fontSize={[16, 13]}
          fontWeight={500}
          color={active ? 'xwhite.500' : 'xwhite.050'}
          _hover={{
            color: 'xwhite.500',
            bg: active ? 'xblack.016' : 'xwhite.010',
          }}
          bg={active ? 'xblack.016' : ''}
          px={2}
          py={[2, 3 / 2]}
          display="flex"
          alignItems="center"
          borderRadius="md"
          onClick={onClick}
        >
          {icon}
          <Text ml={2}>{text}</Text>
          {badge}
        </ChakraLink>
      </NextLink>
    </ListItem>
  )
}
Example #5
Source File: Mdx.js    From codeursenseine.com with MIT License 5 votes vote down vote up
LI = (props) => <ListItem {...props} />
Example #6
Source File: Dropzone.js    From web-client with Apache License 2.0 5 votes vote down vote up
AttachmentsDropzone = ({ parentType, parentId, onUploadFinished = null, attachmentId = null }) => {
    const onFileDrop = (newFiles) => {
        setAcceptedFiles(newFiles);
    };

    const {
        getRootProps, getInputProps,
        isDragActive, isDragAccept, isDragReject
    } = useDropzone({ onDrop: onFileDrop });

    const [acceptedFiles, setAcceptedFiles] = useState([]);

    const onUploadButtonClick = ev => {
        const formData = new FormData();
        formData.append('parentType', parentType);
        formData.append('parentId', parentId);
        acceptedFiles.forEach(file => {
            formData.append('attachment[]', file);
        })

        let uri = '/attachments';
        if (attachmentId) {
            formData.append('attachmentId', attachmentId);
            uri = `/attachments/${attachmentId}`;
        }

        secureApiFetch(uri, {
            method: 'POST',
            body: formData
        })
            .then(() => {
                setAcceptedFiles([]);
                if (onUploadFinished) onUploadFinished();
            })
            .catch(err => console.error(err));
    }

    const style = useMemo(() => ({
        ...baseStyle,
        ...(isDragActive ? activeStyle : {}),
        ...(isDragAccept ? acceptStyle : {}),
        ...(isDragReject ? rejectStyle : {})
    }), [
        isDragActive,
        isDragAccept,
        isDragReject
    ]);

    return (
        <div className="container">
            <div {...getRootProps({ style })}>
                <input {...getInputProps()} />
                <p>Drag and drop some files here, or click to select files</p>
            </div>
            <aside>
                {acceptedFiles.length === 0 && <div>(upload list empty)</div>}
                {acceptedFiles.length > 0 && <List spacing={3}>{acceptedFiles.map(file => (
                    <ListItem key={file.path}>
                        <FontAwesomeIcon color='var(--primary-color)' icon={faUpload} /> {file.path} - {file.size} bytes
                    </ListItem>
                ))}</List>}
            </aside>
            <hr />
            <PrimaryButton onClick={onUploadButtonClick} disabled={acceptedFiles.length === 0}>Upload file(s)</PrimaryButton>
        </div>
    );
}
Example #7
Source File: ExportForm.js    From web-client with Apache License 2.0 5 votes vote down vote up
ExportForm = () => {
    const [entities] = useFetch('/system/exportables');

    const [exportButtonDisabled, setExportButtonDisabled] = useState(true);

    const [entitiesToExport, setEntitiesToExport] = useState([]);

    const onEntitiesSelectionChange = ev => {
        const selectedEntities = Array.from(ev.target.selectedOptions, option => option.value);
        setExportButtonDisabled(selectedEntities.length === 0);
        setEntitiesToExport(selectedEntities);
    };

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

        const url = `/system/data?` + new URLSearchParams({ entities: entitiesToExport }).toString();
        secureApiFetch(url, { method: 'GET' })
            .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();
            })
    };

    return <div>
        <h3>Export system data</h3>

        <div style={{ marginTop: '5px', marginBottom: '5px' }}>
            Notes:
            <UnorderedList>
                <ListItem>Select one or more entities to export.</ListItem>
                <ListItem>The data will be returned in JSON format.</ListItem>
                <ListItem>This operation can take up to one minute to complete depending on the size of your database.</ListItem>
            </UnorderedList>
        </div>

        <Select multiple style={{ width: '80%', height: 250 }} onChange={onEntitiesSelectionChange}>
            {entities && entities.map(entity => <option key={entity.key} value={entity.key}>{entity.description}</option>)}
        </Select>
        <br />
        <PrimaryButton disabled={exportButtonDisabled}
            onClick={onExportButtonClick} leftIcon={<IconDownload />}>Export</PrimaryButton>
    </div>
}
Example #8
Source File: ImportForm.js    From web-client with Apache License 2.0 5 votes vote down vote up
ImportForm = () => {

    const [importResponse, setImportResponse] = useState(null);
    const [importButtonDisabled, setImportButtonDisabled] = useState(true);

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

        const resultFileInput = document.getElementById('importFile');
        const formData = new FormData();
        formData.append('importFile', resultFileInput.files[0]);
        secureApiFetch('/system/data', {
            method: 'POST',
            body: formData
        })
            .then(resp => resp.json())
            .then(resp => {
                setImportResponse(resp);
            })
            .catch(err => console.error(err));
    }

    const onImportFileChange = ev => {
        ev.preventDefault();
        const selectedFiles = ev.target.files;

        setImportButtonDisabled(selectedFiles.length === 0);
    }

    return <div>
        <h3>Import system data</h3>
        <form>
            <div>
                Notes:
                <UnorderedList>
                    <ListItem>Everything on the file will be attempted to be imported.</ListItem>
                    <ListItem>If there is an error the import process will continue resulting on a partial import.</ListItem>
                    <ListItem>If there are missing attributes, Reconmap will attempt to use defaults instead.</ListItem>
                    <ListItem>Example of the files to import can be found on the following url: <ExternalLink href="https://github.com/reconmap/reconmap/tree/master/imports">https://github.com/reconmap/reconmap/tree/master/imports</ExternalLink> </ListItem>
                </UnorderedList>
            </div>
            <FormControl id="importFile" isRequired>
                <FormLabel>Import file</FormLabel>
                <Input type="file" onChange={onImportFileChange} accept=".json,.js,application/json,text/json" isRequired />
            </FormControl>

            <PrimaryButton disabled={importButtonDisabled}
                onClick={handleUploadClick} leftIcon={<IconUpload />}>Import</PrimaryButton>
        </form>

        {importResponse &&
            <div>
                <h4>Import completed</h4>

                {importResponse.errors.length > 0 && <ul>
                    {importResponse.errors.map(error => <li style={{ color: 'orange' }}>
                        {error}
                    </li>)}
                </ul>}

                {importResponse.results.length > 0 && <>
                    <p>The number of imports per category are:</p>
                    <ul>
                        {importResponse.results.map(entityResult => {
                            return <li>{entityResult.count} {entityResult.name} ({entityResult.errors.length} errors)</li>
                        })}
                    </ul>
                </>}
            </div>
        }
    </div>
}
Example #9
Source File: BecomeMember.js    From DAOInsure with MIT License 4 votes vote down vote up
function BecomeMember() {
	const { signerAddress, provider, signer } = useContext(Web3Context);
	const { isOpen, onOpen, onClose } = useDisclosure();

	const [latitude, setLatitude] = useState();
	const [longitude, setLongitude] = useState();

	const handleChange = (e, setter) => {
		setter(e.target.value);
	};

	const web3 = new Web3(provider);

	console.log(web3);

	const joinDao = async () => {
		let contract = new ethers.Contract(
			SUPERAPP_CONTRACT_ADDRESS,
			SUPERAPP_CONTRACT_ABI,
			signer
		);

		const walletAddress = await window.ethereum.request({
			method: "eth_requestAccounts",
			params: [
				{
					eth_accounts: {},
				},
			],
		});

		// this sdk has a lot of changes (breaking changes) from the version we used.
		const sf = new SuperfluidSDK.Framework({
			ethers: provider,
		});

		await sf.initialize();

		// creating user from unlocked address. token is super token.
		const carol = sf.user({
			address: walletAddress[0],
			token: "0x5D8B4C2554aeB7e86F387B4d6c00Ac33499Ed01f",
		});

		// creating a flow, user data can contain arbitary data.
		await carol.flow({
			recipient: SUPERAPP_CONTRACT_ADDRESS,
			flowRate: "3858024691358",
			userData: web3.eth.abi.encodeParameters(
				["string", "string"],
				[latitude, longitude]
			),
		});

		// details of the user like incoming and outgoing flow rates, and the various active flows along with types.
		const details = await carol.details();
		console.log(details);

		// // Call the host with the batch call parameters
		// await sf.host.batchCall(createPlayBatchCall(100));
		function createPlayBatchCall(upgradeAmount = 0) {
			return [
				[
					202, // upgrade 100 daix to play the game
					"0x5D8B4C2554aeB7e86F387B4d6c00Ac33499Ed01f",
					// adding latitude and longitude to the encoded data.
					contract.interface.encodeFunctionData("setCoordinates", [
						parseInt(latitude),
						parseInt(longitude),
					]),
				],
				[
					1, // approve the ticket fee
					{
						token: "0x5D8B4C2554aeB7e86F387B4d6c00Ac33499Ed01f", // Super Tokens only
						amount: "1000000000000000000",
						spender: SUPERAPP_CONTRACT_ADDRESS,
					},
				],
			];
		}

		// Call the host with the batch call parameters
		await sf.host.batchCall(createPlayBatchCall(100));
	};

	return (
		<VStack spacing={5} mt='20px'>
			<Modal
				isOpen={isOpen}
				onClose={onClose}
				closeOnOverlayClick={false}>
				<ModalOverlay />
				<ModalContent>
					<ModalHeader>Enter the following Details</ModalHeader>
					<ModalCloseButton />
					<ModalBody>
						<HStack>
							<Input
								onChange={(e) => handleChange(e, setLatitude)}
								placeholder='Latitude'
							/>
							<Input
								onChange={(e) => handleChange(e, setLongitude)}
								placeholder='Longitude'
							/>
						</HStack>
					</ModalBody>
					<ModalFooter>
						<Button onClick={joinDao} colorScheme='whatsapp'>
							Join DAO (10 DAIx / Month)
						</Button>
					</ModalFooter>
				</ModalContent>
			</Modal>
			<Heading fontSize='32px'>Become A Member</Heading>
			<Heading fontSize='24px'>How it works?</Heading>
			<UnorderedList>
				<ListItem>
					DAOInsure provides insurances to its members based on DAO
					voting
				</ListItem>
				<ListItem>
					DAO members stream insurance premium to the treasury.
				</ListItem>
				<ListItem>
					In exchange for premium paid the members get voting power.
				</ListItem>
				<ListItem>
					Use voting power to approve other fellow member's claim.
				</ListItem>
			</UnorderedList>
			<Heading fontSize='24px'>
				Become A Member just 10 DAIx / Month
			</Heading>
			{signerAddress ? (
				<Button colorScheme='whatsapp' onClick={onOpen}>
					Join the DAO
				</Button>
			) : (
				<GreenTag>Please connect wallet first</GreenTag>
			)}
		</VStack>
	);
}
Example #10
Source File: Todo.js    From benjamincarlson.io with MIT License 4 votes vote down vote up
Todo = () => {
    const toast = useToast()
    const { colorMode } = useColorMode()
    const { isOpen, onOpen, onClose } = useDisclosure()

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

    const borderColor = {
        light: 'gray.200',
        dark: 'gray.600',
    }

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

    const myTodos = [
        {
            completed: false,
            title: 'Improve Final Cut Pro skills ?',
        },
        {
            completed: false,
            title: 'Finish my degree ?',
        },
        {
            completed: false,
            title: 'Grow my YouTube channel ?',
        },
        {
            completed: false,
            title: 'Grow coffeeclass.io ☕',
        },
    ]

    const [todos, setTodos] = useState(myTodos)
    const [input, setInput] = useState('')
    const removeTodo = todo => {
        setTodos(todos.filter(t => t !== todo))
    }

    const toggleCompleted = todo => {
        todo.completed = !todo.completed
        setTodos([...todos])
    }

    const addTodo = () => {
        setTodos(todos.concat({
            completed: false,
            title: input,
        }))
        setInput('')
    }

    return (
        <>
            <Box as="section" w="100%" mt={10} mb={20}>
                <Stack spacing={4} w="100%">
                    <Heading letterSpacing="tight" size="lg" fontWeight={700} as="h2">Todo List ?</Heading>
                    <Text color={colorSecondary[colorMode]}>Here is a list of things I plan to accomplish over the next year. Try it out yourself!</Text>
                    <InputGroup size="md" mt={4} borderColor="gray.500" borderColor={borderColor[colorMode]}>
                        <InputLeftElement
                            pointerEvents="none"
                            children={<Search2Icon color={useColorModeValue("gray.500", "gray.600")} />}
                        />
                        <Input
                            aria-label="Enter a Todo!"
                            placeholder="Improve Python skills ?"
                            value={input}
                            onChange={e => setInput(e.target.value)}
                        />
                        <InputRightElement width="6.75rem">
                            <Button
                                aria-label="Add a TODO!"
                                fontWeight="bold"
                                h="1.75rem"
                                size="md"
                                colorScheme="gray"
                                mr={2}
                                variant="outline"
                                px={10}
                                onClick={() => {
                                    if (input == '')
                                        toast({
                                            title: 'Whoops! There\'s an error!',
                                            description: "Input can't be empty!",
                                            status: "error",
                                            duration: 2000,
                                            isClosable: true,
                                        })
                                    else {
                                        addTodo(input)
                                    }
                                }}
                            >
                                Add Todo!
                            </Button>
                        </InputRightElement>
                    </InputGroup>
                    <Flex flexDir="column">
                        {todos.map((todo, index) => (
                            <Flex
                                key={index}
                                justify="space-between"
                                align="center"
                                my={1}
                            >
                                <Flex align="center">
                                    <Icon fontSize="xl" mr={2} as={ChevronRightIcon} color={colorSecondary[colorMode]} />
                                    <Tooltip label={`Click "${todo.title}" to mark as completed.`} placement="top" hasArrow>
                                        <Text color={colorSecondary[colorMode]} textDecor={todo.completed && "line-through"} _hover={{ cursor: 'pointer' }} onClick={() => toggleCompleted(todo)}>{todo.title}</Text>
                                    </Tooltip>
                                </Flex>
                                <Tooltip label={`Delete "${todo.title}"`} placement="top" hasArrow>
                                    <IconButton aria-label={`Delete "${todo.title}" from Todo list.`} icon={<DeleteIcon color="red.400" />} onClick={() => removeTodo(todo)} />
                                </Tooltip>
                            </Flex>
                        ))}
                    </Flex>
                    <Flex align="center">
                        <Text onClick={() => setTodos(myTodos)} _hover={{ cursor: 'pointer' }} color={colorSmall[colorMode]}>Reset</Text>
                        <Divider orientation="vertical" mx={2} h={4} />
                        <Text onClick={onOpen} _hover={{ cursor: 'pointer' }} color={colorSmall[colorMode]}>Help</Text>
                    </Flex>
                </Stack>
            </Box>
            <Modal isOpen={isOpen} onClose={onClose}>
                <ModalOverlay />
                <ModalContent>
                    <ModalHeader>Todo List Help</ModalHeader>
                    <ModalCloseButton />
                    <ModalBody>
                        <OrderedList>
                            <ListItem>
                                <Text fontWeight="bold">Add a Todo</Text>
                                <Text>Input your Todo and click the "Add Todo!" button to add a new Todo.</Text>
                            </ListItem>
                            <ListItem>
                                <Text fontWeight="bold">Reset</Text>
                                <Text>Click the "Reset" button to reset the list.</Text>
                            </ListItem>
                            <ListItem>
                                <Text fontWeight="bold">Delete</Text>
                                <Text>Click the "Delete" button to delete a Todo.</Text>
                            </ListItem>
                            <ListItem>
                                <Text fontWeight="bold">Completed</Text>
                                <Text>Click a Todo to mark it as completed.</Text>
                            </ListItem>
                            <ListItem>
                                <Text fontWeight="bold">View Code</Text>
                                <Text>Click the "View Code" button to view the code on GitHub for this simple TODO list.</Text>
                            </ListItem>
                        </OrderedList>
                        <Divider my={6} />
                        <Text><strong>Current state of Todo List:</strong> [{todos.map(t => { return `{"${t.title}",${t.completed}},` })}]</Text>
                    </ModalBody>

                    <ModalFooter>
                        <Button colorScheme="blue" mr={3} onClick={onClose}>
                            Close
                        </Button>
                        <Link
                            href="https://github.com/bjcarlson42/benjamincarlson.io/blob/master/components/Todo.js"
                            _hover={{ textDecor: 'none' }}
                            isExternal
                        >
                            <Button variant="ghost">View Code</Button>
                        </Link>
                    </ModalFooter>
                </ModalContent>
            </Modal>
        </>
    )
}
Example #11
Source File: get-invitation.js    From idena-web with MIT License 4 votes vote down vote up
export default function GetInvitation() {
  const router = useRouter()
  const {t} = useTranslation()

  const [nickname, setNickname] = useState('')

  const failToast = useFailToast()
  const successToast = useSuccessToast()

  const [code, setCode] = useState()
  const [isWaiting, setIsWaiting] = useState(false)

  const size = useBreakpointValue(['lg', 'md'])

  const invitationCodeRef = useRef()

  const {scrollTo: scrollToCode} = useScroll(invitationCodeRef)

  const getCode = async () => {
    setIsWaiting(true)
    const name = nickname.startsWith('@') ? nickname.substring(1) : nickname

    try {
      const {invitation} = await getInvitationCode(name, cookie.get('refId'))
      setCode(invitation)
      successToast(t('Your invitation code has been generated successfully!'))
      scrollToCode()
    } catch (e) {
      failToast(e.message)
    } finally {
      setIsWaiting(false)
    }
  }

  return (
    <Layout showHamburger={false}>
      <Page>
        <Flex
          align="center"
          alignSelf="stretch"
          justify={['center', 'space-between']}
          mb={[8, 2]}
          w={['100%', null]}
        >
          <PageTitle
            fontSize={['base', 'xl']}
            fontWeight={['bold', 500]}
            mb={0}
          >
            {t('How to get an invitation')}
          </PageTitle>
          <CloseButton
            color={['blue.500', 'inherit']}
            size="lg"
            position={['absolute', 'inherit']}
            right={2}
            onClick={() => router.push('/home')}
          />
        </Flex>
        <Flex
          direction="column"
          maxW="480px"
          w={['100%', null]}
          fontSize={['mdx', 'md']}
        >
          <Text>
            {t(
              'To minimize the probability of a Sybil attack, the pace of network growth is restricted: Idena network participation is invitation-based. New invitations can be sent out only by validated users. The number of invitations is limited and increases as the network grows.',
              {nsSeparator: '|'}
            )}
          </Text>
          <Text mt={2}>
            {t(
              'Please choose the platform where you have the most active account:',
              {nsSeparator: '|'}
            )}
          </Text>

          <Tabs variant="unstyled" mt={8}>
            <TabList bg={['gray.50', 'white']} p={[1, 0]} borderRadius="md">
              <GetInvitationTab
                iconSelected={<TelegramInvertedIcon />}
                icon={<TelegramIcon />}
                title="Telegram"
              />
              <GetInvitationTab
                iconSelected={<DiscordInvertedIcon />}
                icon={<DiscordIcon />}
                title="Discord"
              />
              <GetInvitationTab
                iconSelected={<TwitterIcon />}
                icon={<TwitterIcon />}
                title="Twitter"
              />
              <GetInvitationTab
                iconSelected={<RedditInvertedIcon />}
                icon={<RedditIcon />}
                title="Reddit"
              />
            </TabList>
            <TabPanels>
              <GetInvitationTabPanel>
                <GetInvitationTabTitle>Telegram</GetInvitationTabTitle>
                <Text>
                  <Trans t={t} i18nKey="joinIdenaTelegram">
                    Join the official{' '}
                    <Link
                      href="https://t.me/IdenaNetworkPublic"
                      target="_blank"
                      color="blue.500"
                    >
                      Idena Telegram group
                    </Link>{' '}
                    and request an invitation code from the community.
                  </Trans>
                </Text>
              </GetInvitationTabPanel>
              <GetInvitationTabPanel>
                <GetInvitationTabTitle>Discord</GetInvitationTabTitle>
                <Text>
                  <Trans t={t} i18nKey="joinIdenaDiscord">
                    Join{' '}
                    <Link
                      href="https://discord.gg/8BusRj7"
                      target="_blank"
                      color="blue.500"
                    >
                      Idena Community Discord
                    </Link>{' '}
                    and request an invitation code from the community in
                    #invite-requests channel.
                  </Trans>
                </Text>
              </GetInvitationTabPanel>
              <GetInvitationTabPanel>
                <GetInvitationTabTitle>Twitter</GetInvitationTabTitle>
                <OrderedList spacing={2}>
                  <ListItem>
                    {t('Follow')}{' '}
                    <Link
                      href="https://twitter.com/IdenaNetwork"
                      target="_blank"
                      color="blue.500"
                    >
                      @IdenaNetwork
                    </Link>{' '}
                  </ListItem>
                  <ListItem>
                    <Stack spacing={4}>
                      <Text>
                        <Trans t={t} i18nKey="joinIdenaTwitterSendTweet">
                          <Link
                            target="_blank"
                            color="blue.500"
                            rel="noreferrer"
                            href="https://twitter.com/intent/tweet?text=I%20want%20to%20join%20%40IdenaNetwork%20to%20become%20a%20validator%20of%20the%20first%20Proof-of-Person%20blockchain%20%23IdenaInvite%0A%0Ahttps://www.idena.io"
                          >
                            Send a tweet
                          </Link>{' '}
                          with a hashtag #IdenaInvite from your account. To get
                          an invite, your account should be older than 1 year or
                          older than two months and have at least 50 followers.
                          The tweet should say:
                        </Trans>
                      </Text>
                      <Flex mt={4} p={[7, 10]} borderRadius="md" bg="gray.50">
                        <Flex direction={['column', 'row']}>
                          <Stack>
                            <Text color="gray.500">
                              I want to join @IdenaNetwork to become a validator
                              of the first Proof-of-Person blockchain
                              #IdenaInvite
                            </Text>
                            <Text>
                              <Link
                                href="https://www.idena.io"
                                target="_blank"
                                color="blue.500"
                              >
                                https://www.idena.io
                              </Link>
                            </Text>
                          </Stack>
                          <GetInvitationCopyButton
                            ml={[0, 10]}
                            value={
                              'I want to join @IdenaNetwork to become a validator of the first Proof-of-Person blockchain #IdenaInvite\n' +
                              '\n' +
                              'https://www.idena.io'
                            }
                          />
                        </Flex>
                      </Flex>
                    </Stack>
                  </ListItem>
                  <ListItem>
                    <Stack spacing={4} pt={2}>
                      <Text>
                        <Trans t={t} i18nKey="joinIdenaTwitterGetCode">
                          Enter your twitter name and click{' '}
                          <i>Get an invitation code</i> button. The code will be
                          shown automatically.
                        </Trans>
                      </Text>
                      <Stack>
                        <Text color="gray.500" fontWeight="500">
                          {t('Your nickname')}
                        </Text>
                        <GetInvitationTwitterInput
                          value={nickname}
                          onChange={value => setNickname(value)}
                        />
                      </Stack>

                      {code ? (
                        <Flex
                          boxShadow="0 3px 12px 0 rgba(83, 86, 92, 0.1), 0 2px 3px 0 rgba(83, 86, 92, 0.2)"
                          px={10}
                          py={8}
                          borderRadius="lg"
                          position="relative"
                        >
                          <Flex
                            direction={['column', 'row']}
                            justifyContent="space-between"
                            w="100%"
                          >
                            <Stack spacing={0}>
                              <Text color="muted">{t('Invitation code')}</Text>
                              <Text
                                color="gray.500"
                                fontWeight={500}
                                wordBreak="break-all"
                              >
                                {code}
                              </Text>
                            </Stack>
                            <GetInvitationCopyButton
                              value={code}
                              ml={[0, 10]}
                            />
                          </Flex>
                        </Flex>
                      ) : (
                        <Flex>
                          <PrimaryButton
                            ml="auto"
                            onClick={getCode}
                            isLoading={isWaiting}
                            loadingText=""
                            w={['100%', 'auto']}
                            size={size}
                          >
                            {t('Get an invitation code')}
                          </PrimaryButton>
                        </Flex>
                      )}
                      <Box ref={invitationCodeRef}></Box>
                    </Stack>
                  </ListItem>
                </OrderedList>
              </GetInvitationTabPanel>
              <GetInvitationTabPanel>
                <GetInvitationTabTitle>Reddit</GetInvitationTabTitle>
                <Text color="gray.500">
                  <Trans t={t} i18nKey="joinIdenaReddit">
                    Join{' '}
                    <Link
                      href="https://www.reddit.com/r/Idena/"
                      target="_blank"
                      color="blue.500"
                    >
                      Idena subreddit
                    </Link>{' '}
                    and request an invitation code from the community.
                  </Trans>
                </Text>
              </GetInvitationTabPanel>
            </TabPanels>
          </Tabs>
        </Flex>
      </Page>
    </Layout>
  )
}
Example #12
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>
  );
}