@chakra-ui/react#Tag JavaScript Examples

The following examples show how to use @chakra-ui/react#Tag. 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: components.js    From idena-web with MIT License 6 votes vote down vote up
function ProfileTag({children, ...props}) {
  return (
    <Tag
      bg={[null, 'gray.016']}
      borderRadius={[null, 'xl']}
      borderBottomWidth={[1, 0]}
      borderBottomColor="gray.100"
      color="gray.500"
      fontSize={['base', 'sm']}
      px={[null, '3']}
      pt={['2', 0]}
      pb={['2.5', 0]}
      w={['full', null]}
      {...props}
    >
      <Stack direction={['column', 'row']} spacing={['1.5', '1']} w={['full']}>
        {children}
      </Stack>
    </Tag>
  )
}
Example #2
Source File: Podcast.js    From grandcast.fm with Apache License 2.0 6 votes vote down vote up
Podcast = ({ podcast }) => {
  const { title, itunesId, description, artwork, categories } = podcast
  const [subscribeMutation, { data }] = useMutation(PODCAST_SUBSCRIBE)
  return (
    <Flex rounded="lg" borderWidth="2px" m={4}>
      <Box width="200px">
        <Image src={artwork} boxSize="200px" />
        <Button
          width="100%"
          onClick={() =>
            subscribeMutation({ variables: { itunesID: itunesId } })
          }
        >
          <AddIcon />
        </Button>
      </Box>
      <Box m={4} maxWidth="300px">
        <Heading noOfLines={2}>{title}</Heading>
        <Text noOfLines={3}>{description}</Text>
        <Stack isInline>
          {categories.slice(0, 3).map((c) => {
            return <Tag key={c}>{c}</Tag>
          })}
        </Stack>
      </Box>
    </Flex>
  )
}
Example #3
Source File: GreenTag.js    From DAOInsure with MIT License 5 votes vote down vote up
function GreenTag({ children }) {
    return (
        <Tag borderRadius="full" ml={2} color="white" fontWeight="600" backgroundColor="lightgreen">
            {children}
        </Tag>
    )
}
Example #4
Source File: Tags.js    From web-client with Apache License 2.0 5 votes vote down vote up
Tags = ({ values }) => {
    if (!values) return null;

    return JSON.parse(values)
        .map((value, index) => <Tag key={`tag_index_${index}`} size="sm"><Link to={`/search/${value}?entities=commands,vulnerabilities`}>{value}</Link></Tag>);
}
Example #5
Source File: ClaimsList.js    From DAOInsure with MIT License 4 votes vote down vote up
function ClaimsList({ claims }) {
	let history = useHistory();

	return (
		<VStack alignItems='flex-start' width='100%' spacing={4}>
			{claims.map((claim) => {
				return (
					<VStack
						key={claim[0].toNumber()}
						alignItems='flex-start'
						borderStyle='solid'
						borderWidth='1px'
						borderRadius='10px'
						borderColor='whatsapp.500'
						px={6}
						py={4}
						width='100%'>
						<HStack
							justifyItems='flex-start'
							alignItems='flex-start'
							width='100%'>
							<Box>
								<HStack>
									<Box
										borderStyle='solid'
										borderWidth='2px'
										borderRadius='full'
										borderColor='whatsapp.500'
										padding='2px'>
										<Avatar
											size='sm'
											icon={
												<Jazzicon
													diameter='32'
													address={claim[1]}
												/>
											}
										/>
									</Box>
									<Text>{claim[1]}</Text>
									<Tag
										colorScheme='whatsapp'
										fontWeight='600'>
										? : {claim[4].toNumber()}
									</Tag>
									<Tag
										colorScheme='whatsapp'
										fontWeight='600'>
										? : {claim[5].toNumber()}
									</Tag>
								</HStack>
							</Box>
							<Spacer />
						</HStack>
						<Link
							cursor='pointer'
							to={`/voting/${claim[0].toNumber()}`}>
							<Heading fontSize='20px' textColor='whatsapp.500'>
								{claim[2]}
							</Heading>
						</Link>
						<Text>{claim.claimSummary}</Text>
						<Text fontWeight='600'>{claim.startTime}</Text>
					</VStack>
				);
			})}
		</VStack>
	);
}
Example #6
Source File: InformationCards.js    From DAOInsure with MIT License 4 votes vote down vote up
function InformationCards({
	author,
	loadingClaim,
	dateOfIncident,
	ipfsHash,
	yesVotes,
	noVotes,
	rainData,
	memberData,
}) {
	const voters = [""];

	const [openWeatherStats, setOpenWeatherStats] = useState();

	useEffect(() => {
		async function init() {
			let response = await axios.get(
				"https://api.openweathermap.org/data/2.5/onecall/timemachine?lat=32.21&lon=76.32&exclude=minutely,hourly&appid=162ac7d2a16586444f5b2e968f020e4c&dt=1628319601"
			);
			setOpenWeatherStats(response.data.hourly);
		}
		init();
	}, []);

	return (
		<VStack spacing={5}>
			<Card cardTitle='Information'>
				<HStack width='100%'>
					<Text fontWeight='600'>Author</Text>
					<Spacer />
					{loadingClaim ? (
						<Skeleton isLoaded={!loadingClaim}>Author</Skeleton>
					) : (
						<Text>{`${author.substr(0, 7)}...${author.substr(
							-7
						)}`}</Text>
					)}
				</HStack>
				<HStack width='100%'>
					<Text fontWeight='600'>IPFS</Text>
					<Spacer />
					{loadingClaim ? (
						<Skeleton isLoaded={!loadingClaim}>IPFS hash</Skeleton>
					) : (
						<HStack>
							<a
								href={`https://ipfs.io/ipfs/` + ipfsHash}
								target='_blank'>
								<Text>
									{" "}
									{`${ipfsHash.substr(
										0,
										7
									)}...${ipfsHash.substr(-7)}`}{" "}
								</Text>

								<FaExternalLinkAlt size='10px' />
							</a>
						</HStack>
					)}
				</HStack>
				<HStack width='100%'>
					<Text fontWeight='600'>Member location</Text>
					<Spacer />
					{loadingClaim ? (
						<Skeleton isLoaded={!loadingClaim}>Author</Skeleton>
					) : (
						<a
							target='_blank'
							href={
								`https://www.google.co.in/maps/@` +
								memberData.lat +
								`,` +
								memberData.long
							}>
							Map
						</a>
					)}
				</HStack>
			</Card>
			<Card cardTitle='Time'>
				<VStack width='100%'>
					<HStack width='100%'>
						<Text fontWeight='600'>Date Of Incident</Text>
						<Spacer />
						{loadingClaim ? (
							<Skeleton isLoaded={!loadingClaim}>
								Date Of Incident
							</Skeleton>
						) : (
							<HStack>
								<Text>{dateOfIncident}</Text>
							</HStack>
						)}
					</HStack>
				</VStack>
			</Card>
			<ChainlinkCard cardTitle=''>
				<VStack width='100%'>
					<HStack width='100%'>
						<Text fontWeight='600'>Rain data : </Text>
						<Text fontWeight='600'>{rainData} mm</Text>

						<Spacer />
					</HStack>
				</VStack>
			</ChainlinkCard>
			<Card cardTitle='Current Results'>
				<VStack width='100%'>
					<HStack width='100%'>
						<Text fontWeight='600'>Yes</Text>
						<Spacer />
						{loadingClaim ? (
							<Skeleton>vote percent</Skeleton>
						) : (
							<Text fontWeight='600'>
								{(yesVotes / (yesVotes + noVotes)) * 100
									? (yesVotes / (yesVotes + noVotes)) * 100
									: "0"}
								%
							</Text>
						)}
					</HStack>
					<Progress
						width='100%'
						borderRadius='20px'
						background='gray.300'
						height='10px'
						value={
							loadingClaim
								? 0
								: (yesVotes / (yesVotes + noVotes)) * 100
						}
						colorScheme='green'
						size='lg'
					/>
					<HStack width='100%'>
						<Text fontWeight='600'>No</Text>
						<Spacer />
						{loadingClaim ? (
							<Skeleton>vote percent</Skeleton>
						) : (
							<Text fontWeight='600'>
								{(noVotes / (yesVotes + noVotes)) * 100
									? (noVotes / (yesVotes + noVotes)) * 100
									: "0"}
								%
							</Text>
						)}
					</HStack>
					<Progress
						width='100%'
						borderRadius='20px'
						background='gray.300'
						height='10px'
						value={
							loadingClaim ? 0 : noVotes / (yesVotes + noVotes)
						}
						colorScheme='green'
						size='lg'
					/>
				</VStack>
			</Card>
			<Card cardTitle='OpenWeather Analysis'>
				{openWeatherStats ? (
					<>
						{openWeatherStats.map((stat) => {
							return (
								<HStack width='100%'>
									<Text>
										{new Date(parseInt(stat.dt) * 1000)
											.toTimeString()
											.substr(0, 5)}
									</Text>
									<Text>
										{stat.weather[0].description[0].toUpperCase() +
											stat.weather[0].description.substr(
												1
											)}
									</Text>
									<Spacer />
									<Image
										src={`http://openweathermap.org/img/wn/${stat.weather[0].icon}.png`}
									/>
								</HStack>
							);
						})}
					</>
				) : (
					<Spinner margin='auto' />
				)}
			</Card>

			<Card cardTitle='Votes'>
				<VStack width='100%' alignItems='flex-start'>
					{loadingClaim ? (
						<HStack justifyContent='space-between' width='100%'>
							<HStack>
								<SkeletonCircle />
								<Skeleton>Address that voted</Skeleton>
							</HStack>
							<Skeleton>Vote</Skeleton>
							<Skeleton>Voting Power</Skeleton>
						</HStack>
					) : (
						<>
							{voters.map((voter) => {
								return (
									<HStack
										justifyContent='space-between'
										width='100%'
										key={0}>
										<HStack>
											<Avatar
												size='xs'
												icon={
													<Jazzicon
														diameter='24'
														address='0x8Cf24E66d1DC40345B1bf97219856C8140Ce6c69'
													/>
												}
											/>
											<Tag>{`${"0x8Cf24E66d1DC40345B1bf97219856C8140Ce6c69".substr(
												0,
												6
											)}...${"0x8Cf24E66d1DC40345B1bf97219856C8140Ce6c69".substr(
												-5
											)}`}</Tag>
										</HStack>
										<Tag colorScheme='whatsapp'>Yes</Tag>
										<Text>300 DIx</Text>
									</HStack>
								);
							})}
						</>
					)}
				</VStack>
			</Card>
		</VStack>
	);
}
Example #7
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 #8
Source File: VotingPage.js    From DAOInsure with MIT License 4 votes vote down vote up
function VotingPage(props) {
	const { textileClient } = useContext(AppContext);
	const [state, dispatch] = useReducer(stateReducer, {
		currentImage: "",
		sendImage: "",
		message: "",
		messages: [],
		claim: "",
		loadingClaim: true,
		vote: 0,
	});

	const { id } = useParams();

	const {
		allProposalsArray,
		fetchAllProposals,
		voteOnProposal,
		signerAddress,
		claimProposal,
		fetchMemberInfo,
		memberData,
	} = useContext(Web3Context);
	const { getRootProps, getRadioProps } = useRadioGroup({
		name: "Vote",
		defaultValue: "No",
		onChange: (e) => handleRadioChange(e),
	});

	useEffect(() => {
		async function init() {
			const proposalId = allProposalsArray[id][9];

			const myFile = await queryThread(
				textileClient,
				"bafkyspsyykcninhqn4ht6d6jeqmzq4cepy344akmkhjk75dmw36wq4q",
				"claimsData",
				{ claimId: proposalId }
			);

			// const myFile = await fleekStorage.getFileFromHash({
			// 	hash: proposalId,
			// });

			dispatch({ type: ACTIONS.SET_CLAIM, payload: myFile });

			dispatch({ type: ACTIONS.SET_LOADING_CLAIM, payload: false });

			// messages from the chat feature are stored in textile. A single collection of all message but can be distinguished using claimId.
			let messages = await queryThread(
				textileClient,
				"bafkyspsyykcninhqn4ht6d6jeqmzq4cepy344akmkhjk75dmw36wq4q",
				"messagesData",
				{ claimId: id }
			);

			dispatch({ type: ACTIONS.SET_MESSAGES, payload: messages });

			console.log("listening");

			// listener for new messages that are added to the collection.
			let closer = await textileClient.listen(
				ThreadID.fromString(
					"bafkyspsyykcninhqn4ht6d6jeqmzq4cepy344akmkhjk75dmw36wq4q"
				),
				[{ actionTypes: ["CREATE"], collectionName: "messagesData" }],
				(reply, error) => {
					dispatch({
						type: ACTIONS.SET_MESSAGES,
						payload: [reply.instance],
					});
				}
			);

			// close listener
			return function cleanup() {
				closer();
			};
		}
		if (textileClient) {
			init();
		}
	}, [textileClient]);

	useEffect(() => {
		fetchMemberInfo();
	}, []);

	const options = ["Yes", "No"];
	const group = getRootProps();

	const handleImage = ({ target }) => {
		dispatch({ type: ACTIONS.SET_CURR_IMAGE, payload: target.src });
	};

	const handleRadioChange = (e) => {
		if (e == "Yes") {
			dispatch({ type: ACTIONS.SET_VOTE, payload: 1 });
		} else {
			dispatch({ type: ACTIONS.SET_VOTE, payload: 0 });
		}
	};

	const handleMessage = ({ target }) => {
		dispatch({ type: ACTIONS.SET_MESSAGE, payload: target.value });
	};

	const handleSendImageChange = ({ target }) => {
		dispatch({ type: ACTIONS.SET_SEND_IMAGE, payload: target.files[0] });
	};

	const handleSendMessage = async () => {
		let uploadedImage = "";

		// upload image if any in message to slate.
		if (state.sendImage) {
			let result = await uploadToSlate(state.sendImage);
			uploadedImage = `https://slate.textile.io/ipfs/${result.data.cid}`;
		}

		let messageObj = {
			message: state.message,
			image: uploadedImage,
			address: signerAddress,
			claimId: id,
		};

		let resultFromTextile = await addToThread(
			textileClient,
			"bafkyspsyykcninhqn4ht6d6jeqmzq4cepy344akmkhjk75dmw36wq4q",
			"messagesData",
			messageObj
		);
		dispatch({ type: ACTIONS.SET_MESSAGE, payload: "" });
		dispatch({ type: ACTIONS.SET_SEND_IMAGE, payload: "" });
	};

	return (
		<Grid
			px='250px'
			py='20px'
			width='100%'
			templateColumns='3fr 2fr'
			gridGap={5}
			alignItems='flex-start'>
			<VStack alignItems='flex-start' width='100%'>
				{state.loadingClaim ? (
					<>
						<HStack width='100%' justifyContent='space-between'>
							<Skeleton isLoaded={!state.loadingClaim}>
								Loading Claim
							</Skeleton>
							<Skeleton isLoaded={!state.loadingClaim}>
								Claim Status
							</Skeleton>
						</HStack>

						<Skeleton width='100%'>
							<Box height='300px' width='100%'>
								Image
							</Box>
						</Skeleton>
					</>
				) : (
					<>
						<HStack width='100%' justifyContent='space-between'>
							<Heading fontSize='24px'>
								{state.claim.claimTitle}
							</Heading>
							<Tag>Open</Tag>
						</HStack>
						{state.claim.images.length == 0 ? null : (
							<>
								<Box
									mt='10px !important'
									boxShadow='lg'
									borderRadius='10px'>
									<Image
										borderRadius='10px'
										src={state.currentImage}
									/>
								</Box>
								<HStack>
									{state.claim.images.map((image) => {
										return (
											<Image
												onClick={handleImage}
												borderRadius='10px'
												height='70px'
												src={image}
											/>
										);
									})}
								</HStack>
							</>
						)}
						<Text>{state.claim.claimSummary}</Text>
					</>
				)}
				{signerAddress == allProposalsArray[id][1] ? (
					<Box
						_hover={{ boxShadow: "base", transform: "scale(1.01)" }}
						transition='all .3s'
						textColor='white'
						fontWeight='600'
						width='30%'
						backgroundColor='whatsapp.500'
						borderRadius='20px'
						textAlign='center'
						py={2}
						borderColor='whatsapp.500'
						colorScheme='whatsapp'
						onClick={() => claimProposal(id)}>
						Claim
					</Box>
				) : (
					<span> </span>
				)}

				<Card cardTitle='Cast Your Vote'>
					{state.loadingClaim ? (
						<Spinner margin='auto' borderColor='whatsapp.500' />
					) : (
						<>
							<VStack width='100%' {...group}>
								{options.map((value) => {
									const radio = getRadioProps({ value });
									return (
										<RadioCard key={value} {...radio}>
											{value}
										</RadioCard>
									);
								})}
							</VStack>
							<Box
								_hover={{
									boxShadow: "base",
									transform: "scale(1.01)",
								}}
								transition='all .3s'
								textColor='white'
								fontWeight='600'
								width='100%'
								backgroundColor='whatsapp.500'
								borderRadius='20px'
								textAlign='center'
								py={2}
								borderColor='whatsapp.500'
								colorScheme='whatsapp'
								onClick={() => voteOnProposal(id, state.vote)}>
								Vote
							</Box>
						</>
					)}
				</Card>
				<Card cardTitle='Chat'>
					{state.loadingClaim ? (
						<Spinner borderColor='whatsapp.500' margin='auto' />
					) : (
						<VStack
							height='400px'
							spacing={5}
							justifyContent='flex-end'
							width='100%'
							alignItems='flex-start'>
							<VStack
								alignItems='flex-start'
								overflowY='scroll'
								width='100%'>
								{state.messages.map((message) => {
									return (
										<HStack
											key={message._id}
											alignItems='flex-end'>
											<Tooltip
												placement='top'
												hasArrow
												label={`${message.address.substr(
													0,
													6
												)}...${message.address.substr(
													-4
												)}`}>
												<Box
													borderWidth='2px'
													padding='2px'
													borderColor='whatsapp.500'
													borderStyle='solid'
													borderRadius='full'>
													<Avatar
														size='sm'
														icon={
															<Jazzicon
																diameter='32'
																address={
																	message.address
																}
															/>
														}
													/>
												</Box>
											</Tooltip>
											<VStack
												alignItems='flex-start'
												backgroundColor='whatsapp.500'
												color='white'
												borderWidth='1px'
												borderRadius='10px'
												borderColor='whatsapp.500'
												padding={3}>
												{message.image.length > 0 ? (
													<Image
														borderRadius='10px'
														height='200px'
														src={message.image}
													/>
												) : null}
												<Text>{message.message}</Text>
											</VStack>
										</HStack>
									);
								})}
							</VStack>
							<HStack>
								{state.sendImage ? (
									<HStack
										borderColor='whatsapp.500'
										borderWidth='1px'
										padding={2}
										borderRadius='10px'
										key={state.sendImage.name}>
										<MdImage />
										<Text>{state.sendImage.name}</Text>
									</HStack>
								) : null}
							</HStack>

							<HStack width='100%'>
								<InputGroup>
									<Input
										value={state.message}
										onChange={handleMessage}
										borderRadius='20px'
										focusBorderColor='whatsapp.500'
									/>
									<InputRightElement>
										<IconButton
											cursor='pointer'
											as='label'
											htmlFor='image-input'
											colorScheme='whatsapp'
											icon={<ImAttachment />}
										/>
										<input
											onChange={(e) =>
												handleSendImageChange(e)
											}
											type='file'
											id='image-input'
											style={{ display: "none" }}
										/>
									</InputRightElement>
								</InputGroup>
								<Button
									onClick={handleSendMessage}
									colorScheme='whatsapp'>
									Send
								</Button>
							</HStack>
						</VStack>
					)}
				</Card>
			</VStack>
			{state.loadingClaim ? (
				<InformationCards loadingClaim={state.loadingClaim} />
			) : (
				<InformationCards
					author={state.claim.author}
					// startDate={state.claim.startTime}
					dateOfIncident={state.claim.dateOfIncident}
					ipfsHash={allProposalsArray[id].ipfsHash}
					yesVotes={allProposalsArray[id].yesVotes}
					noVotes={allProposalsArray[id].noVotes}
					rainData={allProposalsArray[id].rainData.toNumber()}
					memberData={memberData}
				/>
			)}
		</Grid>
	);
}
Example #9
Source File: BuilderProfileView.jsx    From scaffold-directory with MIT License 4 votes vote down vote up
export default function BuilderProfileView({ serverUrl, mainnetProvider, address, userProvider, userRole }) {
  const { builderAddress } = useParams();
  const { primaryFontColor, secondaryFontColor, borderColor, iconBgColor } = useCustomColorModes();
  const [builder, setBuilder] = useState();
  const [challengeEvents, setChallengeEvents] = useState([]);
  const [isLoadingBuilder, setIsLoadingBuilder] = useState(false);
  const [isBuilderOnBg, setIsBuilderOnBg] = useState(false);
  const [isLoadingTimestamps, setIsLoadingTimestamps] = useState(false);
  const toast = useToast({ position: "top", isClosable: true });
  const toastVariant = useColorModeValue("subtle", "solid");
  const challenges = builder?.challenges ? Object.entries(builder.challenges) : undefined;
  const acceptedChallenges = getAcceptedChallenges(builder?.challenges);
  const isMyProfile = builderAddress === address;

  const fetchBuilder = async () => {
    setIsLoadingBuilder(true);
    const fetchedBuilder = await axios.get(serverUrl + `/builders/${builderAddress}`);
    setBuilder(fetchedBuilder.data);

    try {
      await axios.get(bgBackendUrl + `/builders/${builderAddress}`);
    } catch (e) {
      // Builder Not found in BG
      setIsLoadingBuilder(false);
      return;
    }

    setIsBuilderOnBg(true);
    setIsLoadingBuilder(false);
  };

  useEffect(() => {
    fetchBuilder();
    // eslint-disable-next-line
  }, [builderAddress]);

  useEffect(() => {
    if (!builderAddress) {
      return;
    }

    async function fetchChallengeEvents() {
      setIsLoadingTimestamps(true);
      try {
        const fetchedChallengeEvents = await getChallengeEventsForUser(builderAddress);
        setChallengeEvents(fetchedChallengeEvents.sort(byTimestamp).reverse());
        setIsLoadingTimestamps(false);
      } catch (error) {
        toast({
          description: "Can't get challenges metadata. Please try again",
          status: "error",
          variant: toastVariant,
        });
      }
    }
    fetchChallengeEvents();
    // eslint-disable-next-line
  }, [builderAddress]);

  return (
    <Container maxW="container.xl">
      <SimpleGrid gap={14} columns={{ base: 1, xl: 4 }}>
        <GridItem colSpan={1}>
          <BuilderProfileCard
            builder={builder}
            mainnetProvider={mainnetProvider}
            isMyProfile={isMyProfile}
            userProvider={userProvider}
            fetchBuilder={fetchBuilder}
            userRole={userRole}
          />
        </GridItem>
        {isBuilderOnBg ? (
          <GridItem colSpan={{ base: 1, xl: 3 }}>
            <Box borderColor={borderColor} borderWidth={1} p={5}>
              <Flex direction="column" align="center" justify="center">
                <Image src="/assets/bg.png" mb={3} />
                <Text mb={3} fontSize="lg" fontWeight="bold">
                  This builder has upgraded to BuidlGuidl.
                </Text>
                <Button as={Link} href={`${BG_FRONTEND_URL}/builders/${builderAddress}`} isExternal colorScheme="blue">
                  View their profile on Buidlguidl
                </Button>
              </Flex>
            </Box>
          </GridItem>
        ) : (
          <GridItem colSpan={{ base: 1, xl: 3 }}>
            <HStack spacing={4} mb={8}>
              <Flex borderRadius="lg" borderColor={borderColor} borderWidth={1} p={4} w="full" justify="space-between">
                <Flex bg={iconBgColor} borderRadius="lg" w={12} h={12} justify="center" align="center">
                  <InfoOutlineIcon w={5} h={5} />
                </Flex>
                <div>
                  <Text fontSize="xl" fontWeight="medium" textAlign="right">
                    {acceptedChallenges.length}
                  </Text>
                  <Text fontSize="sm" color={secondaryFontColor} textAlign="right">
                    challenges completed
                  </Text>
                </div>
              </Flex>
              <Flex borderRadius="lg" borderColor={borderColor} borderWidth={1} p={4} w="full" justify="space-between">
                <Flex bg={iconBgColor} borderRadius="lg" w={12} h={12} justify="center" align="center">
                  <InfoOutlineIcon w={5} h={5} />
                </Flex>
                <div>
                  <Text fontSize="xl" fontWeight="medium" textAlign="right">
                    {builder?.function ? (
                      <Tag colorScheme={userFunctionDescription[builder?.function].colorScheme} variant="solid">
                        {userFunctionDescription[builder?.function].label}
                      </Tag>
                    ) : (
                      "-"
                    )}
                  </Text>
                  <Text fontSize="sm" color={secondaryFontColor} textAlign="right">
                    Role
                  </Text>
                </div>
              </Flex>
            </HStack>
            <Flex mb={4}>
              <Text fontSize="2xl" fontWeight="bold">
                Challenges
              </Text>
              <Spacer />
            </Flex>
            {isLoadingBuilder && <BuilderProfileChallengesTableSkeleton />}
            {!isLoadingBuilder &&
              (challenges ? (
                <Box overflowX="auto">
                  <Table>
                    {isMyProfile && (
                      <TableCaption>
                        <Button as={RouteLink} colorScheme="blue" to="/">
                          Start a challenge
                        </Button>
                      </TableCaption>
                    )}
                    <Thead>
                      <Tr>
                        <Th>Name</Th>
                        <Th>Contract</Th>
                        <Th>Live Demo</Th>
                        <Th>Updated</Th>
                        <Th>Status</Th>
                      </Tr>
                    </Thead>
                    <Tbody>
                      {challenges.map(([challengeId, lastSubmission]) => {
                        if (!challengeInfo[challengeId]) {
                          return null;
                        }
                        const lastEventForChallenge = challengeEvents.filter(
                          event => event.payload.challengeId === challengeId,
                        )[0];
                        return (
                          <Tr key={challengeId}>
                            <Td>
                              <Link as={RouteLink} to={`/challenge/${challengeId}`} fontWeight="700" color="teal.500">
                                {challengeInfo[challengeId].label}
                              </Link>
                            </Td>
                            <Td>
                              <Link
                                // Legacy branchUrl
                                href={lastSubmission.contractUrl || lastSubmission.branchUrl}
                                color="teal.500"
                                target="_blank"
                                rel="noopener noreferrer"
                              >
                                Code
                              </Link>
                            </Td>
                            <Td>
                              <Link
                                href={lastSubmission.deployedUrl}
                                color="teal.500"
                                target="_blank"
                                rel="noopener noreferrer"
                              >
                                Demo
                              </Link>
                            </Td>
                            <Td>
                              {isLoadingTimestamps ? (
                                <SkeletonText noOfLines={1} />
                              ) : (
                                <DateWithTooltip timestamp={lastEventForChallenge?.timestamp} />
                              )}
                            </Td>
                            <Td>
                              <ChallengeStatusTag
                                status={lastSubmission.status}
                                comment={lastSubmission.reviewComment}
                                autograding={lastSubmission.autograding}
                              />
                            </Td>
                          </Tr>
                        );
                      })}
                    </Tbody>
                  </Table>
                </Box>
              ) : (
                <Flex
                  justify="center"
                  align="center"
                  borderRadius="lg"
                  borderColor={borderColor}
                  borderWidth={1}
                  py={36}
                  w="full"
                >
                  {isMyProfile ? (
                    <Box maxW="xs" textAlign="center">
                      <Text fontWeight="medium" color={primaryFontColor} mb={2}>
                        Start a new challenge
                      </Text>
                      <Text color={secondaryFontColor} mb={4}>
                        Show off your skills. Learn everything you need to build on Ethereum!
                      </Text>
                      <Button as={RouteLink} colorScheme="blue" to="/">
                        Start a challenge
                      </Button>
                    </Box>
                  ) : (
                    <Box maxW="xs" textAlign="center">
                      <Text color={secondaryFontColor} mb={4}>
                        This builder hasn't completed any challenges.
                      </Text>
                    </Box>
                  )}
                </Flex>
              ))}
          </GridItem>
        )}
      </SimpleGrid>
    </Container>
  );
}
Example #10
Source File: Details.js    From web-client with Apache License 2.0 4 votes vote down vote up
VulnerabilityDetails = () => {
    const navigate = useNavigate();
    const { vulnerabilityId } = useParams();
    const [vulnerability, updateVulnerability] = useFetch(`/vulnerabilities/${vulnerabilityId}`)
    const deleteVulnerability = useDelete(`/vulnerabilities/`)

    const parentType = 'vulnerability';
    const parentId = vulnerabilityId;
    const [attachments, reloadAttachments] = useFetch(`/attachments?parentType=${parentType}&parentId=${parentId}`)

    const handleDelete = async () => {
        const confirmed = await deleteVulnerability(vulnerabilityId);
        if (confirmed)
            navigate('/vulnerabilities')
    }

    const onStatusChange = ev => {
        const [status, substatus] = ev.target.value.split('-');
        secureApiFetch(`/vulnerabilities/${vulnerability.id}`, {
            method: 'PATCH',
            body: JSON.stringify({ status, substatus })
        })
            .then(() => {
                actionCompletedToast("The status has been transitioned.");
                updateVulnerability()
            })
            .catch(err => console.error(err))
    }

    if (!vulnerability) return <Loading />

    if (vulnerability && vulnerability.is_template) {
        return <Navigate to={`/vulnerabilities/templates/${vulnerability.id}`} />
    }

    return <div>
        <div className='heading'>
            <Breadcrumb>
                <Link to="/vulnerabilities">Vulnerabilities</Link>
            </Breadcrumb>
            <HStack alignItems='flex-end'>
                <RestrictedComponent roles={['administrator', 'superuser', 'user']}>
                    <EditButton onClick={(ev) => {
                        ev.preventDefault();
                        navigate(`/vulnerabilities/${vulnerability.id}/edit`)
                    }}>Edit</EditButton>

                    <label>Transition to&nbsp;
                        <Select onChange={onStatusChange} value={vulnerability.status + '-' + vulnerability.substatus}>
                            {VulnerabilityStatuses.map(status =>
                                <option key={`vulnstatus_${status.id}`} value={status.id}>{status.name}</option>
                            )}
                        </Select>
                    </label>

                    <DeleteButton onClick={handleDelete} />
                </RestrictedComponent>
            </HStack>
        </div>
        <article>
            <PageTitle value={`${vulnerability.summary} vulnerability`} />

            <Title type='Vulnerability' title={vulnerability.external_id ? <><strong>{vulnerability.external_id.toUpperCase()}</strong>&nbsp;{vulnerability.summary}</> : vulnerability.summary} icon={<IconFlag />} />
            <Tag size="sm" colorScheme="blue">{vulnerability.visibility}</Tag> <Tags values={vulnerability.tags} />

            <Tabs>
                <TabList>
                    <Tab>Description</Tab>
                    <Tab>Remediation</Tab>
                    <Tab>Notes</Tab>
                    <Tab>Attachments</Tab>
                </TabList>
                <TabPanels>
                    <TabPanel>
                        <VulnerabilityDescriptionPanel vulnerability={vulnerability} />
                    </TabPanel>
                    <TabPanel>
                        <VulnerabilityRemediationPanel vulnerability={vulnerability} />
                    </TabPanel>
                    <TabPanel>
                        <VulnerabilitiesNotesTab vulnerability={vulnerability} />
                    </TabPanel>
                    <TabPanel>
                        <AttachmentsDropzone parentType={parentType} parentId={parentId} onUploadFinished={reloadAttachments} />

                        <h4><IconDocument />Attachment list</h4>
                        <AttachmentsTable attachments={attachments} reloadAttachments={reloadAttachments} />
                    </TabPanel>
                </TabPanels>
            </Tabs>
        </article>

    </div >
}