@chakra-ui/react#Skeleton JavaScript Examples

The following examples show how to use @chakra-ui/react#Skeleton. 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: Card.js    From DAOInsure with MIT License 6 votes vote down vote up
function Card({ cardTitle, backgroundColor, children, isLoading }) {
    return (
        <VStack borderRadius="10px" borderStyle="solid" borderColor="whatsapp.500" borderWidth="1px" width="100%" alignItems="flex-start">
            <Box backgroundColor={backgroundColor} width="100%" borderBottomWidth="1px" borderColor="whatsapp.500" px="20px" py="20px">
                <Skeleton isLoaded={!isLoading}>
                    <Heading fontSize="16px">
                        {cardTitle}
                    </Heading>
                </Skeleton>
                
            </Box>
            <VStack alignItems="flex-start" px="20px" py="20px" width="100%">
                {children}
            </VStack>
        </VStack>
    );
}
Example #2
Source File: ChainlinkCard.js    From DAOInsure with MIT License 6 votes vote down vote up
function Card({ cardTitle, backgroundColor, children, isLoading }) {
  return (
    <VStack
      borderRadius="10px"
      borderStyle="solid"
      borderColor="blue"
      borderWidth="1px"
      width="100%"
      alignItems="flex-start"
    >
      <Box
        backgroundColor={backgroundColor}
        width="100%"
        borderBottomWidth="1px"
        borderColor="blue"
        px="15px"
        py="15px"
      >
        <Skeleton isLoaded={!isLoading}>
          <Heading fontSize="16px">
            {" "}
            <img src={ChainlinkLogo} width="90px" />
          </Heading>
        </Skeleton>
      </Box>
      <VStack alignItems="flex-start" px="20px" py="20px" width="100%">
        {children}
      </VStack>
    </VStack>
  );
}
Example #3
Source File: components.js    From idena-web with MIT License 6 votes vote down vote up
export function CertificateTypeLabel({type}) {
  switch (type) {
    case CertificateType.Easy:
      return (
        <CertificateTypeLabelLayout bg="red.500">
          {CertificateTypeTitle(type)}
        </CertificateTypeLabelLayout>
      )
    case CertificateType.Medium:
      return (
        <CertificateTypeLabelLayout bg="gray.500">
          {CertificateTypeTitle(type)}
        </CertificateTypeLabelLayout>
      )
    case CertificateType.Hard:
      return (
        <CertificateTypeLabelLayout bg="orange.500">
          {CertificateTypeTitle(type)}
        </CertificateTypeLabelLayout>
      )

    default:
      return (
        <Skeleton
          position="absolute"
          transform="rotate(-45deg)"
          w={40}
          h={8}
          top={7}
          left={-9}
        />
      )
  }
}
Example #4
Source File: SkeletonAddress.jsx    From scaffold-directory with MIT License 6 votes vote down vote up
SkeletonAddress = ({ fontSize, w }) => (
  <HStack spacing="20px">
    <Skeleton>
      <span style={{ verticalAlign: "middle" }}>
        <QRPunkBlockie withQr={false} address="0xf39F" w={w ?? 12.5} borderRadius="md" />
      </span>
    </Skeleton>
    <Skeleton>
      <span
        style={{
          verticalAlign: "middle",
          fontSize: fontSize ?? 28,
          fontWeight: "bold",
        }}
      >
        0xf39F
      </span>
    </Skeleton>
  </HStack>
)
Example #5
Source File: ProjectListFull.js    From benjamincarlson.io with MIT License 5 votes vote down vote up
ProjectListFull = () => {
    const [searchValue, setSearchValue] = useState('');
    const { data, error } = useSWR('/api/projects', fetcher)
    if (error) return <div style={{ width: '100%' }}>Failed to load projects! Please check your internet connection. If the error persists, contact me.</div>
    if (!data) return (
        <div style={{ width: '100%' }}>
            <InputGroup mb={4} mr={4} w="100%">
                <Input
                    aria-label="Search by name, description, and language"
                    placeholder="Search by name, description, and language"
                />
                <InputRightElement children={<SearchIcon color="gray.500" />} />
            </InputGroup>
            <SimpleGrid minChildWidth="300px" spacing="40px">
                {[...Array(10)].map((_, i) => (
                    <Skeleton key={i} h="250px" />
                ))}
            </SimpleGrid>
        </div>
    )

    const filteredProjects = Object(data.repos)
        .filter((project) =>
            project?.name?.toLowerCase().includes(searchValue.toLowerCase())
            || project?.description?.toLowerCase().includes(searchValue.toLowerCase())
            || project?.language?.toLowerCase().includes(searchValue.toLowerCase())
        )
        .sort(
            (a, b) =>
                Number(b.stars) - Number(a.stars)
        )

    return (
        <>
            <InputGroup mb={4} mr={4} w="100%">
                <Input
                    aria-label="Search by name, description, and language"
                    onChange={(e) => setSearchValue(e.target.value)}
                    placeholder="Search by name, description, and language"
                />
                <InputRightElement children={<SearchIcon color="gray.500" />} />
            </InputGroup>
            <SimpleGrid minChildWidth="300px" spacing="40px">
                {!filteredProjects.length && <Text>No projects found for "<strong>{searchValue}</strong>"!</Text>}
                {filteredProjects
                    .map((p, index) => (
                        <ProjectCard
                            key={index}
                            title={p.name}
                            description={p.description}
                            repoHref={p.url}
                            languageColor={getLanguageColor(p.language)}
                            language={p.language}
                            starCount={p.stars}
                            stargazersUrl={p.stargazers_url}
                            homepage={p.homepage}
                        />
                    ))}
            </SimpleGrid>
        </>
    )
}
Example #6
Source File: NewsSkeleton.js    From sided.news.web with MIT License 5 votes vote down vote up
export default function NewsSkeleton({}) {
  return (
    <div className={styles.news}>
      <div className={styles.left_col}>
        <Skeleton
          height="100%"
          style={{
            borderTopLeftRadius: "20px",
            borderBottomLeftRadius: "20px",
          }}
        />
      </div>

      <div className={styles.right_col}>
        <div className={styles.news_title}>
          <SkeletonText mt="4" noOfLines={4} spacing="4" />
        </div>

        <div>
          <div className={styles.buttons}>
            <div>
              <Button colorScheme="teal" size="xs">
                Read More
              </Button>
            </div>
            <div>
              <Link href="/">
                <Button colorScheme="teal" size="xs" variant="outline">
                  Source
                </Button>
              </Link>
            </div>
          </div>
          <div className={styles.date}>
            {" "}
            <Skeleton height="16px" />
          </div>
        </div>
      </div>
    </div>
  );
}
Example #7
Source File: components.js    From idena-web with MIT License 5 votes vote down vote up
function FullSkeleton(props) {
  return <Skeleton w="full" {...props} />
}
Example #8
Source File: BuilderProfileCard.jsx    From scaffold-directory with MIT License 5 votes vote down vote up
BuilderProfileCardSkeleton = ({ isLoaded, children }) => (
  <Skeleton isLoaded={isLoaded}>{isLoaded ? children() : <SkeletonText mt="4" noOfLines={4} spacing="4" />}</Skeleton>
)
Example #9
Source File: BuilderProfileChallengesTableSkeleton.jsx    From scaffold-directory with MIT License 5 votes vote down vote up
BuilderProfileChallengesTableSkeleton = () => (
  <Box overflowX="auto">
    <Table>
      <Thead>
        <Tr>
          <Th w="30%">Name</Th>
          <Th>Contract</Th>
          <Th>Live Demo</Th>
          <Th>Updated</Th>
          <Th>Status</Th>
        </Tr>
      </Thead>
      <Tbody>
        {[1, 2].map(lineNumber => {
          return (
            <Tr key={lineNumber}>
              <Td>
                <SkeletonText noOfLines={1} py={2} />
              </Td>
              <Td>
                <SkeletonText noOfLines={1} w="50%" />
              </Td>
              <Td>
                <SkeletonText noOfLines={1} w="50%" />
              </Td>
              <Td>
                <SkeletonText noOfLines={1} />
              </Td>
              <Td>
                <Skeleton h={6} w={20} borderRadius="full">
                  Submitted
                </Skeleton>
              </Td>
            </Tr>
          );
        })}
      </Tbody>
    </Table>
  </Box>
)
Example #10
Source File: SubmissionReviewTableSkeleton.jsx    From scaffold-directory with MIT License 5 votes vote down vote up
BuildsTableSkeleton = () => (
  <Box overflowX="auto">
    <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>
        {[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>
                <HStack spacing={3}>
                  <Skeleton startColor="red.100" endColor="red.500">
                    <Button type="button" size="xs">
                      Reject
                    </Button>
                  </Skeleton>
                  <Skeleton startColor="green.100" endColor="green.500">
                    <Button type="button" style={{ marginRight: 10 }} size="xs">
                      Approve
                    </Button>
                  </Skeleton>
                </HStack>
              </Td>
            </Tr>
          );
        })}
      </Tbody>
    </Table>
  </Box>
)
Example #11
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 #12
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 #13
Source File: MakeClaim.js    From DAOInsure with MIT License 4 votes vote down vote up
function MakeClaim() {
	const [currentImage, setCurrentImage] = useState(undefined);
	const [images, setImages] = useState([]);
	const [isPageLoading, setIsPageLoading] = useState(false);
	const { textileClient } = useContext(AppContext);
	const [claimTitle, setClaimTitle] = useState();
	const [claimSummary, setClaimSummary] = useState();
	const [dateOfIncident, setDateOfIncident] = useState();
	const [startTime, setStartTime] = useState();

	const web3Context = useContext(Web3Context);
	const {
		createProposal,
		signerAddress,
		claimableAmount,
		getClaimableAmount,
	} = web3Context;

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

	const handleImage = async (e) => {
		console.log("uploading");
		let file = e.target.files[0];
		try {
			let result = await uploadToSlate(file);
			setImages([
				...images,
				{
					isUploading: false,
					url: `https://slate.textile.io/ipfs/${result.data.cid}`,
				},
			]);
			setCurrentImage(`https://slate.textile.io/ipfs/${result.data.cid}`);
			console.log("uploaded");
		} catch (e) {
			console.log(e);
		}
	};

	const handleCurrentImage = (e) => {
		e.preventDefault();
		setCurrentImage(e.target.src);
	};

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

	const handleClaimSubmit = async (e) => {
		e.preventDefault();
		let imageUrls = images.map((image) => {
			return image.url;
		});
		let claimObj = {
			images: imageUrls,
			claimTitle,
			claimSummary,
			dateOfIncident,
			claimAmount: claimableAmount,
			author: signerAddress,
		};
		console.log(claimObj);

		// tried using fleek instead of threadDB.
		// let response = await fleekStorage.upload({
		// 	apiKey: "3aFyv9UlnpyVvuhdoy+WMA==",
		// 	apiSecret: "vUREhYRSH5DP8WehKP+N8jTLoOJUBw+RA9TPLUKneK8=",
		// 	key: uuidv4(),
		// 	data: JSON.stringify(claimObj),
		// });

		// adding claim data to threadDB.
		let response = await addToThread(
			textileClient,
			"bafkyspsyykcninhqn4ht6d6jeqmzq4cepy344akmkhjk75dmw36wq4q",
			"claimsData",
			claimObj
		);

		// create proposal on contract basically store the hash.
		createProposal(
			claimTitle,
			(new Date(dateOfIncident).getTime() / 1000).toString(),
			response.hash
		);
	};

	return (
		<Grid
			paddingBottom='20px'
			pt='20px'
			height='100%'
			px='250px'
			width='100%'
			templateColumns='2fr 1fr'
			gridGap={5}
			alignItems='flex-start'>
			<VStack width='100%' alignItems='flex-start'>
				<Skeleton isLoaded={!isPageLoading}>
					<Heading as='h4' fontSize='28px'>
						Make a Claim
					</Heading>
				</Skeleton>
				<form style={{ width: "100%" }}>
					<VStack width='100%' spacing={5} alignItems='flex-start'>
						<input
							multiple
							onChange={(e) => handleImage(e)}
							type='file'
							style={{ display: "none" }}
							id='image-input'
							accept='image/*'
						/>
						{images.length == 0 ? (
							isPageLoading ? (
								<Spinner
									colorScheme='whatsapp'
									color='whatsapp.500'
									alignSelf='center'
								/>
							) : (
								<Box
									cursor='pointer'
									as='label'
									htmlFor='image-input'
									px='35px'
									width='100%'
									borderRadius='10px'
									height='70px'
									borderWidth='1px'
									borderStyle='solid'
									borderColor='whatsapp.500'>
									<VStack
										height='100%'
										width='100%'
										justifyContent='center'>
										<TiPlus style={{ fill: "#22C35E" }} />
										<Text fontWeight='600' color='#22C35E'>
											Image
										</Text>
									</VStack>
								</Box>
							)
						) : (
							<>
								<Box
									mt='10px !important'
									boxShadow='lg'
									borderRadius='10px'>
									<Image
										borderRadius='10px'
										src={currentImage}
									/>
								</Box>
								<HStack width='100%' overflowX='scroll'>
									{images.map((image, index) => {
										return image.isUploading ? (
											<Spinner key={index} />
										) : (
											<Image
												key={image.url}
												onClick={(e) => {
													handleCurrentImage(e);
												}}
												borderRadius='10px'
												height='70px'
												src={image.url}
											/>
										);
									})}
									<Box
										cursor='pointer'
										as='label'
										htmlFor='image-input'
										px='35px'
										borderRadius='10px'
										height='70px'
										borderWidth='1px'
										borderStyle='solid'
										borderColor='whatsapp.500'>
										<VStack
											height='100%'
											width='100%'
											justifyContent='center'>
											<TiPlus
												style={{ fill: "#22C35E" }}
											/>
											<Text
												fontWeight='600'
												color='#22C35E'>
												Image
											</Text>
										</VStack>
									</Box>
								</HStack>
							</>
						)}

						<VStack spacing={5} width='100%'>
							<FormControl isRequired>
								<Skeleton isLoaded={!isPageLoading}>
									<FormLabel>Claim Title</FormLabel>
								</Skeleton>
								<Skeleton isLoaded={!isPageLoading}>
									<Input
										onChange={(e) =>
											handleInputChange(e, setClaimTitle)
										}
									/>
								</Skeleton>
							</FormControl>
							<FormControl isRequired>
								<Skeleton isLoaded={!isPageLoading}>
									<FormLabel>Summary of Incident</FormLabel>
								</Skeleton>
								<Skeleton isLoaded={!isPageLoading}>
									<Textarea
										onChange={(e) =>
											handleInputChange(
												e,
												setClaimSummary
											)
										}
										row='10'
									/>
								</Skeleton>
								<Skeleton isLoaded={!isPageLoading}>
									<FormHelperText>
										Try to precise
									</FormHelperText>
								</Skeleton>
							</FormControl>
							<VStack width='100%'>
								<HStack width='100%'>
									<FormControl isRequired>
										<Skeleton isLoaded={!isPageLoading}>
											<FormLabel>
												Date of Incident
											</FormLabel>
										</Skeleton>
										<Skeleton isLoaded={!isPageLoading}>
											<Input
												onChange={(e) =>
													handleInputChange(
														e,
														setDateOfIncident
													)
												}
												type='date'
											/>
										</Skeleton>
									</FormControl>
								</HStack>
							</VStack>
							<Button
								onClick={(e) => handleClaimSubmit(e)}
								isLoading={isPageLoading}
								mt='30px !important'
								width='100%'
								textTransform='uppercase'
								type='submit'
								colorScheme='whatsapp'>
								Submit Claim
							</Button>
						</VStack>
					</VStack>
				</form>
			</VStack>
			<VStack width='100%'>
				<Card isLoading={isPageLoading} cardTitle='Claimable Amount'>
					<Skeleton isLoaded={!isPageLoading}>
						<Heading
							textColor='whatsapp.500'
							fontSize='24px'
							as='h3'>
							{parseFloat(claimableAmount).toFixed(6)} DAI
						</Heading>
					</Skeleton>
				</Card>
			</VStack>
		</Grid>
	);
}
Example #14
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 #15
Source File: sidebar.js    From idena-web with MIT License 4 votes vote down vote up
function ActionPanel({onClose}) {
  const {t} = useTranslation()

  const router = useRouter()

  const epoch = useEpoch()
  const [identity] = useIdentity()
  const onboardingPopoverPlacement = useBreakpointValue(['top', 'right'])

  const [
    currentOnboarding,
    {showCurrentTask, dismissCurrentTask},
  ] = useOnboarding()

  useEffect(() => {
    if (
      eitherState(
        currentOnboarding,
        onboardingShowingStep(OnboardingStep.StartTraining),
        onboardingShowingStep(OnboardingStep.ActivateInvite)
      )
    )
      onClose()
  }, [currentOnboarding, onClose])

  if (!epoch) {
    return (
      <Stack spacing={[2, '1px']} mt={6}>
        <Block
          title={t('My current task')}
          roundedTop="md"
          roundedBottom={['md', 'none']}
        >
          <Skeleton
            h={[4, '13px']}
            mt={[1, '3.5px']}
            mb={[1, '3px']}
            borderRadius="sm"
            startColor="#72767A"
            endColor="#6A6E72"
          />
        </Block>
        <Block
          title={t('Next validation')}
          roundedBottom="md"
          roundedTop={['md', 'none']}
        >
          <Skeleton
            h={[4, '13px']}
            mt={[1, '3.5px']}
            mb={[1, '3px']}
            borderRadius="sm"
            startColor="#72767A"
            endColor="#6A6E72"
          />
        </Block>
      </Stack>
    )
  }

  const eitherOnboardingState = (...states) =>
    eitherState(currentOnboarding, ...states)

  const {currentPeriod, nextValidation} = epoch

  const isPromotingNextOnboardingStep =
    currentPeriod === EpochPeriod.None &&
    (eitherOnboardingState(
      onboardingPromotingStep(OnboardingStep.StartTraining),
      onboardingPromotingStep(OnboardingStep.ActivateInvite),
      onboardingPromotingStep(OnboardingStep.ActivateMining)
    ) ||
      (eitherOnboardingState(
        onboardingPromotingStep(OnboardingStep.Validate)
      ) &&
        [IdentityStatus.Candidate, IdentityStatus.Newbie].includes(
          identity.state
        )) ||
      (eitherOnboardingState(
        onboardingPromotingStep(OnboardingStep.CreateFlips)
      ) &&
        [IdentityStatus.Newbie].includes(identity.state)))

  return (
    <Stack spacing={[2, '1px']} mt={6}>
      {currentPeriod !== EpochPeriod.None && (
        <Block
          title={t('Current period')}
          roundedTop="md"
          roundedBottom={['md', 'none']}
        >
          {currentPeriod}
        </Block>
      )}
      <ChakraBox
        cursor={isPromotingNextOnboardingStep ? 'pointer' : 'default'}
        onClick={() => {
          if (
            eitherOnboardingState(
              OnboardingStep.StartTraining,
              OnboardingStep.ActivateInvite,
              OnboardingStep.ActivateMining
            )
          )
            router.push('/home')
          if (eitherOnboardingState(OnboardingStep.CreateFlips))
            router.push('/flips/list')

          showCurrentTask()
        }}
      >
        <PulseFrame
          isActive={isPromotingNextOnboardingStep}
          roundedTop={[
            'md',
            currentPeriod === EpochPeriod.None ? 'md' : 'none',
          ]}
          roundedBottom={[
            'md',
            currentPeriod !== EpochPeriod.None ? 'md' : 'none',
          ]}
        >
          <Block
            title={t('My current task')}
            roundedTop={[
              'md',
              currentPeriod === EpochPeriod.None ? 'md' : 'none',
            ]}
            roundedBottom={[
              'md',
              currentPeriod !== EpochPeriod.None ? 'md' : 'none',
            ]}
          >
            <CurrentTask
              epoch={epoch.epoch}
              period={currentPeriod}
              identity={identity}
            />
          </Block>
        </PulseFrame>
      </ChakraBox>

      {currentPeriod === EpochPeriod.None && (
        <OnboardingPopover
          isOpen={eitherOnboardingState(
            onboardingShowingStep(OnboardingStep.Validate)
          )}
          placement={onboardingPopoverPlacement}
        >
          <PopoverTrigger>
            <ChakraBox
              bg={
                eitherOnboardingState(
                  onboardingShowingStep(OnboardingStep.Validate)
                )
                  ? 'rgba(216, 216, 216, .1)'
                  : 'transparent'
              }
              position="relative"
              zIndex="docked"
            >
              <Block
                title={t('Next validation')}
                roundedBottom="md"
                roundedTop={['md', 'none']}
              >
                {formatValidationDate(nextValidation)}
                <Menu autoSelect={false} mr={1}>
                  <MenuButton
                    rounded="md"
                    _hover={{bg: 'unset'}}
                    _expanded={{bg: 'brandGray.500'}}
                    _focus={{outline: 0}}
                    position="absolute"
                    top={1}
                    right={1}
                    py={1.5}
                    px={1 / 2}
                  >
                    <MoreIcon boxSize={5} />
                  </MenuButton>
                  <MenuList
                    placement="bottom-end"
                    border="none"
                    shadow="0 4px 6px 0 rgba(83, 86, 92, 0.24), 0 0 2px 0 rgba(83, 86, 92, 0.2)"
                    rounded="lg"
                    py={2}
                    minWidth="145px"
                  >
                    <MenuItem
                      color="brandGray.500"
                      fontWeight={500}
                      px={3}
                      py={2}
                      _hover={{bg: 'gray.50'}}
                      _focus={{bg: 'gray.50'}}
                      _selected={{bg: 'gray.50'}}
                      _active={{bg: 'gray.50'}}
                      onClick={() => {
                        openExternalUrl(
                          buildNextValidationCalendarLink(nextValidation)
                        )
                      }}
                    >
                      <PlusSquareIcon
                        boxSize={5}
                        mr={3}
                        color="brandBlue.500"
                      />
                      Add to calendar
                    </MenuItem>
                  </MenuList>
                </Menu>
              </Block>
            </ChakraBox>
          </PopoverTrigger>
          <Portal>
            <OnboardingPopoverContent
              display={
                eitherOnboardingState(
                  onboardingShowingStep(OnboardingStep.Validate)
                )
                  ? 'flex'
                  : 'none'
              }
              title={t('Schedule your next validation')}
              maxW="sm"
              additionFooterActions={
                <Button
                  variant="unstyled"
                  onClick={() => {
                    openExternalUrl(
                      'https://medium.com/idena/how-do-i-start-using-idena-c49418e01a06'
                    )
                  }}
                >
                  {t('Read more')}
                </Button>
              }
              onDismiss={dismissCurrentTask}
            >
              <Stack spacing={5}>
                <OnboardingPopoverContentIconRow
                  icon={<TelegramIcon boxSize={6} />}
                >
                  <Trans i18nKey="onboardingValidateSubscribe" t={t}>
                    <OnboardingLinkButton href="https://t.me/IdenaAnnouncements">
                      Subscribe
                    </OnboardingLinkButton>{' '}
                    to the Idena Announcements (important updates only)
                  </Trans>
                </OnboardingPopoverContentIconRow>
                <OnboardingPopoverContentIconRow
                  icon={<SyncIcon boxSize={5} />}
                >
                  {t(
                    `Sign in into your account 15 mins before the validation starts.`
                  )}
                </OnboardingPopoverContentIconRow>
                <OnboardingPopoverContentIconRow
                  icon={<TimerIcon boxSize={5} />}
                >
                  {t(
                    `Solve the flips quickly when validation starts. The first 6 flips must be submitted in less than 2 minutes.`
                  )}
                </OnboardingPopoverContentIconRow>
                <OnboardingPopoverContentIconRow
                  icon={<GalleryIcon boxSize={5} />}
                >
                  <Trans i18nKey="onboardingValidateTest" t={t}>
                    <OnboardingLinkButton
                      onClick={() => {
                        dismissCurrentTask()
                        router.push('/try')
                      }}
                    >
                      Test yourself
                    </OnboardingLinkButton>{' '}
                    before the validation
                  </Trans>
                </OnboardingPopoverContentIconRow>
              </Stack>
            </OnboardingPopoverContent>
          </Portal>
        </OnboardingPopover>
      )}
    </Stack>
  )
}