@chakra-ui/react#Grid JavaScript Examples

The following examples show how to use @chakra-ui/react#Grid. 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: Footer.jsx    From realtime-chat-supabase-react with Apache License 2.0 6 votes vote down vote up
export default function Footer() {
  return (
    <Box position="fixed" bottom="0" width="100%">
      <MessageForm />

      <Grid
        gridTemplateColumns="auto 1fr"
        textAlign="center"
        alignItems="center"
        py="4px"
        px="30px"
        height="40px"
        bg="white"
      >
        <GridItem justifySelf="start">
          {/* Built by{" "} */}
          {/* <a href="http://shimon-wosner.vercel.app" target="_blank"> */}
          <a
            href="https://twitter.com/shwosner"
            target="_blank"
            rel="noreferrer"
          >
            <FaTwitter style={{ display: "inline" }} />
            @shwosner
          </a>
        </GridItem>
        <GridItem justifySelf="end">
          <a
            href="https://github.com/shwosner/realtime-chat-supabase-react"
            target="_blank"
            rel="noreferrer"
          >
            <FaGithub style={{ display: "inline" }} /> Source code
          </a>
        </GridItem>
      </Grid>
    </Box>
  );
}
Example #2
Source File: Message.jsx    From realtime-chat-supabase-react with Apache License 2.0 5 votes vote down vote up
export default function Message({ message, isYou }) {
  const countyCode =
    message.country && message.country !== "undefined"
      ? message.country.toLowerCase()
      : "";
  return (
    <Box display="grid" justifyItems={isYou ? "end" : "start"}>
      <Grid
        templateRows="30px 1fr 25px"
        templateColumns="1fr"
        w="70%"
        px="3"
        py="2"
        borderRadius="5px"
        borderTopLeftRadius={isYou ? "5px" : "0"}
        borderTopRightRadius={isYou ? "0" : "5px"}
        bg={isYou ? "#dbfff9" : "#edf3f9"}
        mt="5"
        position="relative"
        _after={{
          position: "absolute",
          content: "''",
          width: 0,
          height: 0,
          borderStyle: "solid",
          borderWidth: isYou ? "0px 0px 10px 10px" : "0px 10px 10px 0",
          borderColor: isYou
            ? "transparent transparent transparent #dbfff9"
            : "transparent #edf3f9 transparent transparent",
          top: 0,
          left: isYou ? "auto" : "-10px",
          right: isYou ? "-10px" : "auto",
        }}
      >
        <GridItem
          fontWeight="500"
          fontSize="md"
          justifySelf="start"
          color="gray.500"
          mb="2"
        >
          <span>{message.username} </span>
          {message.is_authenticated && (
            <MdVerified
              color="#1d9bf0"
              style={{ display: "inline", marginRight: "5px" }}
            />
          )}
          {countyCode && (
            <Box display="inline-block" fontSize="10px">
              from {message.country}{" "}
              <img
                style={{ display: "inline-block", marginTop: "-4px" }}
                src={`/flags/${countyCode}.png`}
                alt={message.country}
              />
            </Box>
          )}
        </GridItem>
        <GridItem
          justifySelf="start"
          textAlign="left"
          wordBreak="break-word"
          fontSize="md"
          fontFamily="Montserrat, sans-serif"
        >
          {message.text}
        </GridItem>
        <GridItem
          color="gray"
          fontSize="10px"
          justifySelf="end"
          alignSelf="end"
        >
          {dayjs(message.timestamp).fromNow()}
        </GridItem>
      </Grid>
    </Box>
  );
}
Example #3
Source File: Header.jsx    From realtime-chat-supabase-react with Apache License 2.0 5 votes vote down vote up
export default function Header() {
  const { username, setUsername, auth, randomUsername } = useAppContext();
  return (
    <Grid
      templateColumns="max-content 1fr min-content"
      justifyItems="center"
      alignItems="center"
      bg="white"
      position="sticky"
      top="0"
      zIndex="10"
      borderBottom="20px solid #edf2f7"
    >
      <GridItem justifySelf="start" m="2">
        <Image src="/logo.png" height="30px" ml="2" />
      </GridItem>
      {auth.user() ? (
        <>
          <GridItem justifySelf="end" alignSelf="center" mr="4">
            Welcome <strong>{username}</strong>
          </GridItem>
          <Button
            marginRight="4"
            size="sm"
            variant="link"
            onClick={() => {
              const { error } = auth.signOut();
              if (error) return console.error("error signOut", error);
              const username = randomUsername();
              setUsername(username);
              localStorage.setItem("username", username);
            }}
          >
            Log out
          </Button>
        </>
      ) : (
        <>
          <GridItem justifySelf="end" alignSelf="end">
            <NameForm username={username} setUsername={setUsername} />
          </GridItem>
          <Button
            size="sm"
            marginRight="2"
            colorScheme="teal"
            rightIcon={<FaGithub />}
            variant="outline"
            onClick={() =>
              auth.signIn({
                provider: "github",
              })
            }
          >
            Login
          </Button>
        </>
      )}
    </Grid>
  );
}
Example #4
Source File: MeetupLayout.js    From codeursenseine.com with MIT License 4 votes vote down vote up
MeetupLayout = ({ children, title }) => {
  const data = useStaticQuery(graphql`
    {
      sponsors: allFile(
        filter: {
          sourceInstanceName: { eq: "sponsors" }
          childMdx: { frontmatter: { isMeetupSponsor: { eq: true } } }
        }
        sort: { order: ASC, fields: childMdx___frontmatter___name }
      ) {
        nodes {
          childMdx {
            frontmatter {
              name
              link
              logo {
                publicURL
              }
            }
          }
        }
      }
      associations: allFile(
        filter: {
          sourceInstanceName: { eq: "associations" }
          internal: {}
          extension: { eq: "mdx" }
        }
        sort: { fields: childMdx___frontmatter___name }
      ) {
        nodes {
          childMdx {
            frontmatter {
              name
              link
              logo {
                publicURL
              }
            }
          }
        }
      }
    }
  `);

  return (
    <Layout theme="meetups">
      <Seo title={title} />
      <Grid templateColumns={{ base: "1fr", md: "2.5fr 1fr" }} gap={8}>
        <Box>{children}</Box>
        <Stack spacing={10}>
          <Stack spacing={6}>
            <Heading as="h2" size="lg" fontWeight="normal" mb={8}>
              Sponsors meetups
            </Heading>
            <Grid templateColumns="1fr 1fr" gap={4}>
              {data.sponsors.nodes.map(({ childMdx: sponsor }) => (
                <Card
                  isLink
                  as="a"
                  href={sponsor.frontmatter.link}
                  title={sponsor.frontmatter.name}
                  key={sponsor.frontmatter.name}
                  p={0}
                >
                  <Image
                    src={sponsor.frontmatter.logo.publicURL}
                    alt={sponsor.frontmatter.name}
                  />
                </Card>
              ))}
            </Grid>
          </Stack>
          <Stack spacing={6}>
            <Heading as="h2" size="lg" fontWeight="normal" mb={8}>
              Associations
            </Heading>
            <Grid templateColumns="1fr 1fr" gap={4}>
              {data.associations.nodes.map(({ childMdx: association }) => (
                <Card
                  isLink
                  as="a"
                  href={association.frontmatter.link}
                  title={association.frontmatter.name}
                  key={association.frontmatter.name}
                  p={0}
                >
                  <Flex align="center" justify="center">
                    <Image
                      src={association.frontmatter.logo.publicURL}
                      alt={association.frontmatter.name}
                    />
                  </Flex>
                </Card>
              ))}
            </Grid>
          </Stack>
        </Stack>
      </Grid>
    </Layout>
  );
}
Example #5
Source File: ConferenceCard.js    From codeursenseine.com with MIT License 4 votes vote down vote up
ConferenceCard = ({ conference, speakers }) => {
  const { isOpen, onOpen, onClose } = useDisclosure();

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

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

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

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

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

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

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

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

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

            {conference.childMdx.frontmatter.meetupLink && (
              <DrawerFooter display="flex" flexDirection="column">
                <Button isFullWidth variant="outline" mb={3} onClick={onClose}>
                  Fermer
                </Button>
                <Button
                  colorScheme="brand"
                  as={Link}
                  target="_blank"
                  to={conference.childMdx.frontmatter.meetupLink}
                  isFullWidth
                >
                  S'inscrire
                </Button>
              </DrawerFooter>
            )}
          </DrawerContent>
        </DrawerOverlay>
      </Drawer>
    </Stack>
  );
}
Example #6
Source File: index.js    From codeursenseine.com with MIT License 4 votes vote down vote up
Meetups = ({ data }) => {
  const meetups = data.meetups.nodes.filter(
    (meetup) =>
      meetup.childMdx &&
      meetup.childMdx.frontmatter &&
      meetup.childMdx.frontmatter.meetup_date !== null
  );

  if (process.env.GATSBY_ARCHIVE) {
    return <RedirectCodeursEnSeine path="/meetups" />;
  }

  return (
    <Layout theme="meetups">
      <Seo
        title="Meetups"
        meta={[
          {
            property: `og:image`,
            content: `${process.env.GATSBY_ORIGIN}/images/meetups/social.jpg`,
          },
        ]}
      />
      <Grid templateColumns={{ base: "1fr", md: "2.5fr 1fr" }} gap={8}>
        <Box>
          <Stack spacing={6}>
            <Heading as="h1" mb={6}>
              Tous les meetups
            </Heading>
            {meetups.map(({ childMdx: meetup, name }) => (
              <Card key={name} as={Link} to={generateMeetupLink(meetup)} isLink>
                <Stack>
                  <Box>
                    <Heading
                      as="h3"
                      color="brand.700"
                      size="lg"
                      fontWeight="normal"
                    >
                      {parse(meetup.frontmatter.title)}
                    </Heading>
                    {meetup.frontmatter.excerpt !== "" && (
                      <Text>{meetup.frontmatter.excerpt}</Text>
                    )}
                  </Box>
                  <Box>
                    <Text fontWeight="bold">
                      Meetup le {meetup.frontmatter.meetup_date} de{" "}
                      {meetup.frontmatter.meetup_start_time} à{" "}
                      {meetup.frontmatter.meetup_end_time}
                    </Text>
                    <Text color="gray.500">
                      {meetup.frontmatter.meetup_location}
                    </Text>
                  </Box>
                </Stack>
              </Card>
            ))}
          </Stack>
        </Box>
        <Stack spacing={10}>
          <Stack spacing={6}>
            <Heading as="h2" size="lg" fontWeight="normal" mb={8}>
              Sponsors meetups
            </Heading>
            <Grid templateColumns="1fr 1fr" gap={4}>
              {data.sponsors.nodes.map(({ childMdx: sponsor }) => (
                <Card
                  isLink
                  as="a"
                  href={sponsor.frontmatter.link}
                  title={sponsor.frontmatter.name}
                  key={sponsor.frontmatter.name}
                  p={0}
                >
                  <Image
                    src={sponsor.frontmatter.logo.publicURL}
                    alt={sponsor.frontmatter.name}
                  />
                </Card>
              ))}
            </Grid>
            <a
              href="https://www.devoxx.fr/"
              target="_blank"
              rel="noopener noreferrer"
            >
              <Image
                src="/images/meetups/devoxx-france-logo-2022-carre.png"
                alt="Devoxx France 2022"
              />
            </a>
          </Stack>
          <Stack spacing={6}>
            <Heading as="h2" size="lg" fontWeight="normal" mb={8}>
              Associations
            </Heading>
            <Grid templateColumns="1fr 1fr" gap={4}>
              {data.associations.nodes.map(({ childMdx: association }) => (
                <Card
                  isLink
                  as="a"
                  href={association.frontmatter.link}
                  title={association.frontmatter.name}
                  key={association.frontmatter.name}
                  p={0}
                >
                  <Flex align="center" justify="center">
                    <Image
                      src={association.frontmatter.logo.publicURL}
                      alt={association.frontmatter.name}
                    />
                  </Flex>
                </Card>
              ))}
            </Grid>
          </Stack>
        </Stack>
      </Grid>
    </Layout>
  );
}
Example #7
Source File: index.js    From codeursenseine.com with MIT License 4 votes vote down vote up
Organisers = ({ pageContext }) => {
  const { organisers } = pageContext;

  const socials = [
    { name: "twitter", icon: <FaTwitter /> },
    { name: "linkedin", icon: <FaLinkedin /> },
    { name: "github", icon: <FaGithub /> },
  ];

  return (
    <Layout theme="ces">
      <OGImage path="/images/ces/social.jpg" />
      <Seo title="Organisateurs" />
      <Heading as="h1" mb={8}>
        Organisateurs
      </Heading>

      <Stack spacing={6}>
        <Heading size="lg">Associations</Heading>
        <Text>
          Codeurs en Seine est une association dont le but est la promotion et
          le partage des pratiques et des nouveautés technologiques entre les
          acteurs du développement informatique.
        </Text>

        <Text>
          En plus de la conférence annuelle Codeurs en Seine, nous organisons
          des meetups et des ateliers tout au long de l'année, sur Rouen et ses
          environs.
        </Text>

        <Text>
          Codeurs en Seine représente le Normandy Java User Group et Normandy
          Agile User Group.
        </Text>

        <Text>
          Elle est également une étape de l'
          <A href="http://www.agiletour.org/">Agile Tour</A>.
        </Text>
        <Heading size="lg">Équipe</Heading>
        <Text mb={8}>
          Codeurs en Seine est propulsé par une équipe de bénévoles passionnés :
        </Text>
        <Grid templateColumns="repeat(auto-fit, minmax(6rem, 1fr))" gap={6}>
          {organisers.map((organiser) => (
            <Stack
              alignItems="center"
              key={organiser.childMdx.frontmatter.name}
            >
              <AspectRatio ratio={1} w="6em" maxW="100%">
                <Image
                  fallbackSrc="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAQAAAC1HAwCAAAAC0lEQVR42mNkYAAAAAYAAjCB0C8AAAAASUVORK5CYII="
                  src={organiser.childMdx.frontmatter.image.publicURL}
                  alt={organiser.childMdx.frontmatter.name}
                  boxShadow="brand"
                  objectFit="cover"
                  borderRadius={4}
                />
              </AspectRatio>
              <Text textAlign="center" fontSize="sm">
                {organiser.childMdx.frontmatter.name}
              </Text>
              <Flex flexWrap="wrap">
                {socials.map(
                  (social) =>
                    organiser.childMdx.frontmatter[social.name] && (
                      <IconButton
                        key={social.name}
                        as="a"
                        target="_blank"
                        href={organiser.childMdx.frontmatter[social.name]}
                        aria-label={`${organiser.childMdx.frontmatter.name} ${social.name}`}
                        icon={social.icon}
                        variant="ghost"
                        colorScheme="brand"
                        size="sm"
                        d="inline-flex"
                      />
                    )
                )}
              </Flex>
            </Stack>
          ))}
        </Grid>
      </Stack>
    </Layout>
  );
}
Example #8
Source File: index.js    From codeursenseine.com with MIT License 4 votes vote down vote up
SponsorsPage = ({ pageContext }) => {
  const { sponsors } = pageContext;

  const data = useStaticQuery(graphql`
    {
      placeholderImage: file(
        relativePath: { eq: "ces/dossier-sponsoring.jpg" }
      ) {
        childImageSharp {
          gatsbyImageData(width: 250, quality: 80, layout: CONSTRAINED)
        }
      }
    }
  `);

  const sponsorLevels = ["platinium", "gold", "silver", "bronze"];

  return (
    <Layout theme="ces">
      <OGImage path="/images/ces/social.jpg" />
      <Seo title="Sponsors" />
      <Heading as="h1" mb={8}>
        Devenir Sponsor
      </Heading>

      <Grid templateColumns={["1fr", "1fr", "1fr 2fr"]} gap={8} mb={8}>
        <Box maxWidth="250px">
          <A
            d="block"
            boxShadow="brand"
            overflow="hidden"
            borderRadius="md"
            href="https://drive.google.com/file/d/1zclVxBxeUZFUxX2kxVXCoAW8CnFr3p40/view?usp=sharing"
            title="Dossier de sponsoring"
            target="_blank"
          >
            <GatsbyImage
              image={data.placeholderImage.childImageSharp.gatsbyImageData}
              alt="Première page du dossier de sponsoring"
            />
          </A>
        </Box>
        <Box>
          <Stack spacing={8}>
            <Text>
              Codeurs en Seine est à la recherche de sponsors pour proposer un
              événement d'une qualité toujours meilleure.
            </Text>
            <Text>
              Les partenaires des éditions précédentes ont confirmé la
              visibilité offerte par ce sponsoring, surtout dans le cadre d'une
              politique de recrutement.
            </Text>
            <Text>
              Si vous souhaitez soutenir l'événement, téléchargez{" "}
              <A
                href="https://drive.google.com/file/d/1zclVxBxeUZFUxX2kxVXCoAW8CnFr3p40/view?usp=sharing"
                target="_blank"
              >
                le dossier de sponsoring
              </A>
              ,{" "}
              <A
                href="https://docs.google.com/document/d/14dtwH8QfzXuvPddlbo2fYgRy78RPtwwU1vPsH9tdgr4/edit?usp=sharing"
                target="_blank"
              >
                la convention de sponsoring
              </A>{" "}
              et contactez-nous à l'adresse{" "}
              <A href="mailto:[email protected]">
                [email protected]
              </A>
              .
            </Text>
            <ButtonGroup>
              <Button
                as="a"
                href="https://drive.google.com/file/d/1zclVxBxeUZFUxX2kxVXCoAW8CnFr3p40/view?usp=sharing"
                target="_blank"
                colorScheme="brand"
              >
                Dossier de sponsoring
              </Button>
              <Box display="flex" flexDir="column">
                <Button
                  as="a"
                  href="https://docs.google.com/document/d/14dtwH8QfzXuvPddlbo2fYgRy78RPtwwU1vPsH9tdgr4/edit?usp=sharing"
                  target="_blank"
                  colorScheme="brand"
                  variant="outline"
                >
                  Convention de sponsoring
                </Button>
                <Button
                  as="a"
                  href="https://docs.google.com/document/d/1oI6vAZBttTuSgxHH__LCVS1XV8j7wdiozc1TEzuVEhk/edit?usp=sharing"
                  target="_blank"
                  colorScheme="brand"
                  variant="outline"
                  marginTop={4}
                >
                  ?? Sponsorship agreement
                </Button>
              </Box>
            </ButtonGroup>
          </Stack>
        </Box>
      </Grid>
      <Divider mb={6} />
      <Stack spacing={6}>
        {sponsorLevels.map((level) => {
          const thisLevelSponsors = sponsors.filter(
            (sponsor) => sponsor.frontmatter.sponsor === level
          );

          return (
            thisLevelSponsors.length > 0 && (
              <Stack spacing={6} key={level}>
                <Heading size="lg" color="brand.700" fontWeight="normal">
                  Sponsors {level}
                </Heading>
                <SimpleGrid columns={{ base: 1, sm: 2, lg: 3 }} gap={8}>
                  {thisLevelSponsors.map((sponsor, index) => (
                    <SponsorCard
                      key={index}
                      name={sponsor.frontmatter.name}
                      link={sponsor.frontmatter.link}
                      logoSrc={sponsor.frontmatter?.logo?.publicURL}
                      excerpt={sponsor.excerpt}
                      isDonator={sponsor.frontmatter.isDonator}
                    >
                      {sponsor.body}
                    </SponsorCard>
                  ))}
                </SimpleGrid>
                <Divider />
              </Stack>
            )
          );
        })}
      </Stack>
    </Layout>
  );
}
Example #9
Source File: ActivityPage.js    From DAOInsure with MIT License 4 votes vote down vote up
function ActivityPage() {
	const [data, setData] = useState();

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

			let datas = [];

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

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

	return (
		<Grid px='250px' gridGap='10px' py='20px'>
			<Heading fontSize='24px' color='whatsapp.500'>
				Members
			</Heading>
			<Box height='400px'>
				{loadingData ? <Spinner /> : <MyResponsivePie data={data} />}
			</Box>
			<Table>
				<Thead>
					<Tr>
						<Th>Address</Th>
						<Th>outFlowed</Th>
					</Tr>
				</Thead>
				<Tbody>
					{data == undefined ? (
						<Spinner />
					) : (
						<>
							{data.map((data, index) => {
								return (
									<Tr>
										<Td>
											<GreenTag>{data.id}</GreenTag>
										</Td>
										<Td>{data.value}</Td>
									</Tr>
								);
							})}
						</>
					)}
				</Tbody>
			</Table>
		</Grid>
	);
}
Example #10
Source File: ClaimsPage.js    From DAOInsure with MIT License 4 votes vote down vote up
function ClaimsPage() {
	const { textileClient } = useContext(AppContext);
	const [openClaims, setOpenClaims] = useState();
	const [isLoadingOpenClaims, setIsLoadingOpenClaims] = useState(true);

	const web3Context = useContext(Web3Context);
	const {
		fetchAllProposals,
		allProposalsArray,
		openProposalsArray,
		acceptedProposalsArray,
		rejectedProposalsArray,
		daoMemberCount,
		setDaoMemberCount,
	} = web3Context;

	useEffect(() => {
		async function init() {
			console.log(textileClient);
			if (textileClient) {
				// textile database querying the thread using threadId and collection where claims are present.
				let openClaims = await queryThread(
					textileClient,
					"bafkyspsyykcninhqn4ht6d6jeqmzq4cepy344akmkhjk75dmw36wq4q",
					"claimsData",
					{}
				);
				console.log(openClaims);
				setOpenClaims(openClaims);
				setIsLoadingOpenClaims(false);
			}
		}
		init();
	}, [textileClient]);

	useEffect(() => {
		fetchAllProposals();
		console.log(openProposalsArray);
	}, []);

	return (
		<Grid
			height='calc(100vh - 64px)'
			px='250px'
			py='20px'
			width='100%'
			templateColumns='3fr 1fr'
			gridGap={5}
			alignItems='flex-start'>
			<Tabs variant='soft-rounded' colorScheme='whatsapp'>
				<TabList justifyContent='space-between'>
					<HStack>
						<Tab>
							Open Claims{" "}
							<GreenTag>{openProposalsArray.length}</GreenTag>
						</Tab>
						<Tab variant='solid'>
							Accepted Claims{" "}
							<GreenTag>{acceptedProposalsArray.length}</GreenTag>
						</Tab>
						<Tab variant='solid'>
							Rejected Claims{" "}
							<GreenTag>{rejectedProposalsArray.length}</GreenTag>
						</Tab>
					</HStack>
					<Link to='/makeClaim'>
						<Button colorScheme='whatsapp'>+ Make a Claim</Button>
					</Link>
				</TabList>
				<TabPanels>
					<TabPanel py={4} px={0}>
						<ClaimsList claims={openProposalsArray} />
					</TabPanel>
					<TabPanel py={4} px={0}>
						<ClaimsList claims={acceptedProposalsArray} />
					</TabPanel>
					<TabPanel py={4} px={0}>
						<ClaimsList claims={rejectedProposalsArray} />
					</TabPanel>
				</TabPanels>
			</Tabs>
			<Stats
				claims={
					acceptedProposalsArray.length +
					rejectedProposalsArray.length
				}
				daoMemberCount={daoMemberCount}
			/>
		</Grid>
	);
}
Example #11
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 #12
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 #13
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 #14
Source File: Player.jsx    From bottle-radio with MIT License 4 votes vote down vote up
Player = () => {
  const variables = window._env_ ? window._env_ : { REACT_ICECAST_URL: "" };
  const [playing, setPlaying] = useState(false);
  const [loading, setLoading] = useState(false);
  const [muted, setMuted] = useState(false);
  const [firstLoad, setFirstLoad] = useState(true);
  const [nowPlaying, setNowPlaying] = useState(["No data", "No data"]);
  const [listeners, setListeners] = useState([0, 0]);
  const { colorMode } = useColorMode();
  const colorHover = { light: "white", dark: "black" };
  const { isOpen, onOpen, onClose } = useDisclosure();
  const trackLinks = useSaveTrack(
    nowPlaying[0],
    nowPlaying[1]
  );
  const audioRef = useRef(null);
  const { setPlayer } = useContext(VisualiserContext);

  useEffect(() => {
    const audio = document.getElementById("player");
    if (audio) {
      setPlayer(audioRef);
    }
  }, [setPlayer]);

  useEffect(() => {
    const updateStats = async () => {
      let url = variables.REACT_ICECAST_URL + "status-json.xsl";
      let response = await fetch(url);
      let json = await response.json();
      let track = json.icestats.source.title;
      if (track && track !== "") {
        let artist = track.split(" - ")[0];
        track = track.split(" - ").slice(1).join(" - ");
        setNowPlaying([track, artist]);
      }
      let listeners = json.icestats.source.listeners;
      let peakListeners = json.icestats.source.listener_peak;

      if (listeners && listeners) {
        setListeners([listeners, peakListeners]);
      }
    };
    updateStats();
    setInterval(() => {
      updateStats();
    }, 10000);
  }, [variables.REACT_ICECAST_URL]);

  const togglePlay = () => {
    let player = document.getElementById("player");
    if (firstLoad) {
      setFirstLoad(false);
    }
    if (player.paused) {
      setPlaying(true);
      player.load();
      player.play();
    } else {
      setPlaying(false);
      player.pause();
    }
  };

  const changeVolume = (value) => {
    let player = document.getElementById("player");
    value <= 0 ? setMuted(true) : setMuted(false);
    player.volume = value / 100;
  };

  const TrackModal = (props) => {
    const { modal, setModal } = useContext(ModalContext);

    useEffect(() => {
      if (!modal) {
        setModal(trackLinks);
      }
    }, [modal, setModal]);

    return (
      <div>
        <Modal
          isOpen={isOpen}
          onClose={() => {
            onClose();
            setModal();
          }}
          size="sm"
          isCentered
        >
          <ModalOverlay>
            <ModalContent>
              <ModalCloseButton />
              <ModalBody>
                <Grid templateColumns="1fr 1fr" justifyItems="center" gap={0}>
                  {modal && modal.length > 0 ? (
                    modal.map((link) => (
                      <Link key={link.url} href={link.url} isExternal>
                        <Button variant="ghost">{link.displayName}</Button>
                      </Link>
                    ))
                  ) : (
                    <div>
                      <Spinner size="sm" /> Loading...
                    </div>
                  )}
                </Grid>
              </ModalBody>
            </ModalContent>
          </ModalOverlay>
        </Modal>
      </div>
    );
  };

  return (
    <div>
      <Flex
        direction="column"
        justify="center"
        align="center"
        width="100%"
        height="100%"
      >
        <Box>
          <Grid
            m={2}
            p={2}
            templateColumns="auto 1fr auto"
            alignItems="center"
            gap={1}
          >
            <Box
              gridRow="1/4"
              w="80px"
              h="80px"
              aria-label="Play toggle"
              as={loading ? FaSpinner : playing ? FaPauseCircle : FaPlayCircle}
              onClick={togglePlay}
              _hover={{ color: colorHover[colorMode] }}
              mr={1}
              className={loading ? "icon-spin" : ""}
            />
            <Text m={0} align="center">
              <strong>{nowPlaying[0]}</strong>
            </Text>
            <Text m={0} align="center">
              {nowPlaying[1]}
            </Text>

            <Flex direction="row" justify="center" maxWidth={400} p={2}>
              <Slider
                defaultValue={100}
                min={0}
                max={100}
                step={10}
                onChange={changeVolume}
                width="80px"
              >
                <SliderTrack>
                  <SliderFilledTrack bg="tomato" />
                </SliderTrack>
                <SliderThumb size={2} />
              </Slider>
              <Box
                w="20px"
                h="20px"
                as={muted ? FaVolumeMute : FaVolumeUp}
                ml={3}
              />
              <audio
                id="player"
                crossOrigin="anonymous"
                autoPlay
                preload="none"
                ref={audioRef}
                onPlay={() => setPlaying(true)}
                onPause={() => setPlaying(false)}
                onLoadStart={() => {
                  if (!firstLoad) {
                    setLoading(true);
                  }
                }}
                onCanPlay={() => setLoading(false)}
              >
                <source
                  src={variables.REACT_ICECAST_URL + "radio.mp3"}
                  type="audio/mp3"
                />
                Your browser does not support the audio element.
              </audio>
            </Flex>
            <Text gridColumn="1/4">
              <strong>Listeners: </strong>
              {listeners[0]} <strong>Peak: </strong>
              {listeners[1]}
            </Text>
            <Box gridColumn="3" gridRow="1/4" alignItems="center">
              <Box
                w="25px"
                h="25px"
                as={FaHeart}
                mx={1}
                onClick={onOpen}
                _hover={{ color: "tomato" }}
              />
              {isOpen ? <TrackModal /> : null}
            </Box>
          </Grid>
        </Box>
      </Flex>
    </div>
  );
}
Example #15
Source File: PlayerEmbed.jsx    From bottle-radio with MIT License 4 votes vote down vote up
PlayerEmbed = () => {
  const variables = window._env_ ? window._env_ : { REACT_ICECAST_URL: "" };
  const [playing, setPlaying] = useState(false);
  const [loading, setLoading] = useState(false);
  const [muted, setMuted] = useState(false);
  const [nowPlaying, setNowPlaying] = useState(["No data", "No data"]);
  const { colorMode } = useColorMode();
  const colorHover = { light: "white", dark: "black" };

  useEffect(() => {
    const updateStats = async () => {
      let url = variables.REACT_ICECAST_URL + "status-json.xsl";
      let response = await fetch(url);
      let json = await response.json();
      let track = json.icestats.source.title;
      if (track && track !== "") {
        let artist = track.split(" - ")[0];
        track = track.split(" - ").slice(1).join(" - ");
        setNowPlaying([track, artist]);
      }
    };
    updateStats();
    setInterval(() => {
      updateStats();
    }, 10000);
  }, [variables.REACT_ICECAST_URL]);

  const togglePlay = () => {
    let player = document.getElementById("player");
    if (player.paused) {
      setPlaying(true);
      player.load();
      player.play();
    } else {
      setPlaying(false);
      player.pause();
    }
  };

  const changeVolume = (value) => {
    let player = document.getElementById("player");
    value <= 0 ? setMuted(true) : setMuted(false);
    player.volume = value / 100;
  };

  return (
    <div>
      <Flex
        direction="column"
        justify="center"
        align="center"
        width="100%"
        height="100%"
        bg="transparent"
      >
        <Box>
          <Grid
            m={2}
            p={2}
            templateColumns="auto 1fr"
            alignItems="center"
            gap={1}
          >
            <Box
              gridRow="1/4"
              size="80px"
              aria-label="Play toggle"
              as={loading ? FaSpinner : playing ? FaPauseCircle : FaPlayCircle}
              onClick={togglePlay}
              _hover={{ color: colorHover[colorMode] }}
              mr={1}
              className={loading ? "icon-spin" : ""}
            />
            <Text m={0} align="right">
              <strong>{nowPlaying[0]}</strong>
            </Text>
            <Text m={0} align="right">
              {nowPlaying[1]}
            </Text>

            <Flex direction="row" justify="center" maxWidth={400} p={2}>
              <Slider
                defaultValue={100}
                min={0}
                max={100}
                step={10}
                onChange={changeVolume}
                width={80}
              >
                <SliderTrack style={{ height: "5px" }}>
                  <SliderFilledTrack bg="tomato" />
                </SliderTrack>
                <SliderThumb size={2} />
              </Slider>
              <Box
                w="20px"
                h="20px"
                as={muted ? FaVolumeMute : FaVolumeUp}
                ml={3}
              />
              <audio
                id="player"
                autoPlay
                onPlay={() => setPlaying(true)}
                onPause={() => setPlaying(false)}
                onLoadStart={() => setLoading(true)}
                onLoadedData={() => setLoading(false)}
              >
                <source
                  src={variables.REACT_ICECAST_URL + "radio.mp3"}
                  type="audio/mp3"
                />
                Your browser does not support the audio element.
              </audio>
            </Flex>
          </Grid>
        </Box>
      </Flex>
    </div>
  );
}