@chakra-ui/react#Input JavaScript Examples

The following examples show how to use @chakra-ui/react#Input. 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: podcasts.js    From grandcast.fm with Apache License 2.0 6 votes vote down vote up
Podcasts = () => {
  const [getPodcasts, { data }] = useLazyQuery(PodcastSearchQuery)
  const { isSignedIn } = useAuth()
  const [searchString, setSearchString] = useState('')
  return (
    <Container>
      {!isSignedIn() && <SignIn />}
      {isSignedIn() && (
        <div>
          <FormControl id="podcastsearch">
            <FormLabel>Search podcasts</FormLabel>
            <Flex>
              <Input onChange={(e) => setSearchString(e.target.value)} />
              <Button
                ml={4}
                onClick={() =>
                  getPodcasts({ variables: { searchTerm: searchString } })
                }
              >
                Search
              </Button>
            </Flex>
          </FormControl>
          <VStack>
            {data?.podcastSearch.map((p) => {
              return <Podcast podcast={p} />
            })}
          </VStack>
        </div>
      )}
    </Container>
  )
}
Example #2
Source File: Todos.jsx    From fastapi-react with MIT License 6 votes vote down vote up
function AddTodo() {
  const [item, setItem] = React.useState("")
  const {todos, fetchTodos} = React.useContext(TodosContext)

  const handleInput = event  => {
    setItem(event.target.value)
  }

  const handleSubmit = (event) => {
    const newTodo = {
      "id": todos.length + 1,
      "item": item
    }

    fetch("http://localhost:8000/todo", {
      method: "POST",
      headers: { "Content-Type": "application/json" },
      body: JSON.stringify(newTodo)
    }).then(fetchTodos)
  }

  return (
    <form onSubmit={handleSubmit}>
      <InputGroup size="md">
        <Input
          pr="4.5rem"
          type="text"
          placeholder="Add a todo item"
          aria-label="Add a todo item"
          onChange={handleInput}
        />
      </InputGroup>
    </form>
  )
}
Example #3
Source File: index.js    From codeursenseine.com with MIT License 6 votes vote down vote up
Newsletter = ({ ...props }) => {
  return (
    <Card {...props}>
      <Stack spacing={4}>
        <Text as="strong">
          Renseignez votre email pour recevoir les news de Codeurs en Seine
        </Text>
        <form
          action="https://codeursenseine.us16.list-manage.com/subscribe/post?u=e89c02673c1526190f38a8e68&amp;id=942ec797d0"
          method="post"
          id="mc-embedded-subscribe-form"
          name="mc-embedded-subscribe-form"
          target="_blank"
          noValidate
        >
          <StackInline spacing={4}>
            <Input
              placeholder="[email protected]"
              type="email"
              id="mce-EMAIL"
              name="EMAIL"
              width="auto"
              flexGrow={1}
            />
            <Button
              colorScheme="brand"
              type="submit"
              name="subscribe"
              id="mc-embedded-subscribe"
              flexGrow={{ base: 1, md: 0 }}
            >
              Recevoir les news par email
            </Button>
          </StackInline>
        </form>
      </Stack>
    </Card>
  );
}
Example #4
Source File: SignIn.js    From grandcast.fm with Apache License 2.0 6 votes vote down vote up
SignIn = () => {
  const [username, setUsername] = useState('')
  const [password, setPassword] = useState('')
  const { signIn } = useAuth()

  function onSubmit(e) {
    e.preventDefault()
    signIn({ username, password })
  }

  return (
    <div>
      <FormControl b="1px" id="signin">
        <FormLabel m={4}>Sign In</FormLabel>
        <Input
          m={4}
          type="text"
          placeholder="username"
          onChange={(e) => setUsername(e.target.value)}
        ></Input>
        <Input
          m={4}
          type="password"
          placeholder="password"
          onChange={(e) => setPassword(e.target.value)}
        ></Input>
        <Button m={4} w="100%" onClick={onSubmit} type="submit">
          Log In
        </Button>
      </FormControl>
    </div>
  )
}
Example #5
Source File: Form.js    From web-client with Apache License 2.0 6 votes vote down vote up
DocumentForm = ({ document, onFormSubmit, documentSetter: setNote, isEditForm = false }) => {
    const onFormInputChange = ev => {
        const target = ev.target;
        const name = target.name;
        const value = target.value;

        setNote({
            ...document, [name]: value
        });
    };

    return <form onSubmit={onFormSubmit}>
        <FormControl isRequired>
            <FormLabel htmlFor="title">Title</FormLabel>
            <Input type="text" name="title" id="title" value={document.title || ""} onChange={onFormInputChange} autoFocus />
        </FormControl>

        <FormControl isRequired>
            <FormLabel htmlFor="content">Content (markdown supported)</FormLabel>
            <MarkdownEditor name="content" style={{ width: '100%' }} required value={document.content || ""}
                onChange={onFormInputChange} /><br />
        </FormControl>

        <FormControl>
            <FormLabel htmlFor="visibility">Visibility</FormLabel>
            <Select name="visibility" id="visibility" value={document.visibility} onChange={onFormInputChange} required>
                <option value="private">Private</option>
                <option value="public">Public</option>
            </Select>
        </FormControl>

        <PrimaryButton type="submit">{isEditForm ? "Update" : "Create"}</PrimaryButton>
    </form>
}
Example #6
Source File: Login.js    From GitMarkonics with MIT License 5 votes vote down vote up
function Login() {
  return (
    <>
    <Navbar />
    <div className="login">
      <div className="login__container">
        <div className="login__containerTop">
          <div className="login__img"></div>
          <p>Add a crisp to your bulky documents !!</p>
          <h4>Welcome to the website</h4>
        </div>
        <div className="login__containerBottom">
          <VStack className="input__container" w="65%" m="auto">
            <Heading
              fontSize="1.2rem"
              color="blue.500"
              fontWeight="semibold"
              py={3}
            >
              USER LOGIN
            </Heading>
            <InputGroup w="95%" borderRadius="full" bgColor="gray.200">
              <InputLeftElement
                margin="0 20px"
                pointerEvents="none"
                children={
                  <RiAccountPinBoxFill color="#C6C6E8" fontSize="2.1rem" />
                }
              />
              <Input
                borderRadius="full"
                type="tel"
                placeholder="Username"
                paddingLeft="60px"
              />
            </InputGroup>
            <InputGroup
              className="login__input"
              w="95%"
              borderRadius="full"
              bgColor="gray.200"
            >
              <InputLeftElement
                margin="0 20px"
                pointerEvents="none"
                children={
                  <RiLockPasswordFill color="#C6C6E8" fontSize="2.1rem" />
                }
              />
              <Input
                type="password"
                borderRadius="full"
                placeholder="Password"
                paddingLeft="60px"
              />
            </InputGroup>
            <Link  fontSize="sm" textDecoration="underline" color="blue">
                <a href="/register" >Need Account ?</a>
              </Link>
            <HStack className="login__btn" alignSelf="flex-end">
              <Button
                colorScheme="pink"
                px="6"
                size="sm"
                fontWeight="bold"
                className="loginBtn"
              >
                LOGIN
              </Button>
              <Link  fontSize="sm" textDecoration="underline" color="blue">
                <a href="/forget" >Forgot password?</a>
              </Link>
            </HStack>
          </VStack>
        </div>
      </div>
    </div>
    </>
  );
}
Example #7
Source File: Form.js    From web-client with Apache License 2.0 5 votes vote down vote up
UserForm = ({ isEdit = false, user, userSetter: setUser, onFormSubmit }) => {

    const [passwordGenerationMethod, setPasswordGenerationMethod] = useState('autogenerated');

    const onFormChange = ev => {
        const target = ev.target;
        const name = target.name;
        const value = target.type === 'checkbox' ? target.checked : target.value;
        setUser({ ...user, [name]: value });
    };

    const onPasswordGenerationMethodChange = ev => {
        setPasswordGenerationMethod(ev.target.value);
    }

    return <form onSubmit={onFormSubmit} className="crud">
        <fieldset>
            <legend>Basic information</legend>

            <label>Full name
                <Input type="text" name="full_name" value={user.full_name || ""} onChange={onFormChange} required />
            </label>
            <label>Short bio
                <Input type="text" name="short_bio" value={user.short_bio || ""} onChange={onFormChange}
                    placeholder="DevSecOps, or Project Manager" />
            </label>
            <label>Email
                <Input type="email" name="email" value={user.email || ""} onChange={onFormChange} required />
            </label>
            <label>Role
                <Select name="role" onChange={onFormChange} value={user.role} required>
                    {UserRoles.map(role => <option key={`role_${role.id}`} value={role.id}>{role.name}</option>)}
                </Select>
            </label>
            <label>Properties
                <div>
                    <Checkbox name="active" isChecked={user.active} onChange={onFormChange}>Active</Checkbox>
                    <Checkbox name="mfa_enabled" isChecked={user.mfa_enabled} onChange={onFormChange}>2FA enabled</Checkbox>
                </div>
            </label>
        </fieldset>

        <fieldset>
            <legend>Credentials</legend>
            <label>Username
                <Input type="text" name="username" value={user.username || ""} onChange={onFormChange} autoFocus required />
            </label>
            {!isEdit &&
                <>
                    <label htmlFor="passwordGenerationMethod">Password generation method
                        <Select name="passwordGenerationMethod" onChange={onPasswordGenerationMethodChange}>
                            <option value="auto">Auto-generated</option>
                            <option value="manual">Manual</option>
                        </Select>
                    </label>
                    {passwordGenerationMethod === 'manual' &&
                        <>
                            <label>Password
                                <Input type="password" name="unencryptedPassword" onChange={onFormChange} required />
                            </label>
                            <label>
                                Send email to user
                                <Checkbox name="sendEmailToUser" onChange={onFormChange} />
                            </label>
                        </>
                    }
                </>
            }
        </fieldset>

        <PrimaryButton type="submit">{isEdit ? "Update" : "Create"}</PrimaryButton>
    </form >
}
Example #8
Source File: MessageForm.jsx    From realtime-chat-supabase-react with Apache License 2.0 5 votes vote down vote up
export default function MessageForm() {
  const { supabase, username, country, auth } = useAppContext();
  const [message, setMessage] = useState("");
  const toast = useToast();
  const [isSending, setIsSending] = useState(false);

  const handleSubmit = async (e) => {
    e.preventDefault();
    setIsSending(true);
    if (!message) return;

    setMessage("");

    try {
      const { error } = await supabase.from("messages").insert([
        {
          text: message,
          username,
          country,
          is_authenticated: auth.user() ? true : false,
        },
      ]);

      if (error) {
        console.error(error.message);
        toast({
          title: "Error sending",
          description: error.message,
          status: "error",
          duration: 9000,
          isClosable: true,
        });
        return;
      }
      console.log("Sucsessfully sent!");
    } catch (error) {
      console.log("error sending message:", error);
    } finally {
      setIsSending(false);
    }
  };

  return (
    <Box py="10px" pt="15px" bg="gray.100">
      <Container maxW="600px">
        <form onSubmit={handleSubmit} autoComplete="off">
          <Stack direction="row">
            <Input
              name="message"
              placeholder="Enter a message"
              onChange={(e) => setMessage(e.target.value)}
              value={message}
              bg="white"
              border="none"
              autoFocus
            />
            <IconButton
              // variant="outline"
              colorScheme="teal"
              aria-label="Send"
              fontSize="20px"
              icon={<BiSend />}
              type="submit"
              disabled={!message}
              isLoading={isSending}
            />
          </Stack>
        </form>
        <Box fontSize="10px" mt="1">
          Warning: do not share any sensitive information, it's a public chat
          room ?
        </Box>
      </Container>
    </Box>
  );
}
Example #9
Source File: search.js    From react-table-library with MIT License 5 votes vote down vote up
Component = () => {
  let data = { nodes };

  const chakraTheme = getTheme(DEFAULT_OPTIONS);
  const theme = useTheme(chakraTheme);

  const [search, setSearch] = React.useState('');

  const handleSearch = (event) => {
    setSearch(event.target.value);
  };

  data = {
    nodes: data.nodes.filter((item) => item.name.toLowerCase().includes(search.toLowerCase())),
  };

  const COLUMNS = [
    { label: 'Task', renderCell: (item) => item.name },
    {
      label: 'Deadline',
      renderCell: (item) =>
        item.deadline.toLocaleDateString('en-US', {
          year: 'numeric',
          month: '2-digit',
          day: '2-digit',
        }),
    },
    { label: 'Type', renderCell: (item) => item.type },
    {
      label: 'Complete',
      renderCell: (item) => item.isComplete.toString(),
    },
    { label: 'Tasks', renderCell: (item) => item.nodes?.length },
  ];

  return (
    <div>
      <Stack spacing={10}>
        <InputGroup>
          <InputLeftElement
            pointerEvents="none"
            children={<FaSearch style={{ color: '#4a5568' }} />}
          />
          <Input placeholder="Search Task" value={search} onChange={handleSearch} />
        </InputGroup>
      </Stack>
      <br />

      <Box p={3} borderWidth="1px" borderRadius="lg">
        <CompactTable columns={COLUMNS} data={data} theme={theme} />
      </Box>

      <br />
      <DocumentationSee anchor={'Features/' + key} />
    </div>
  );
}
Example #10
Source File: Todos.jsx    From fastapi-react with MIT License 5 votes vote down vote up
function UpdateTodo({item, id}) {
  const {isOpen, onOpen, onClose} = useDisclosure()
  const [todo, setTodo] = useState(item)
  const {fetchTodos} = React.useContext(TodosContext)

  const updateTodo = async () => {
    await fetch(`http://localhost:8000/todo/${id}`, {
      method: "PUT",
      headers: { "Content-Type": "application/json" },
      body: JSON.stringify({ item: todo })
    })
    onClose()
    await fetchTodos()
  }

  return (
    <>
      <Button h="1.5rem" size="sm" onClick={onOpen}>Update Todo</Button>
      <Modal isOpen={isOpen} onClose={onClose}>
        <ModalOverlay/>
        <ModalContent>
          <ModalHeader>Update Todo</ModalHeader>
          <ModalCloseButton/>
          <ModalBody>
            <InputGroup size="md">
              <Input
                pr="4.5rem"
                type="text"
                placeholder="Add a todo item"
                aria-label="Add a todo item"
                value={todo}
                onChange={e => setTodo(e.target.value)}
              />
            </InputGroup>
          </ModalBody>

          <ModalFooter>
            <Button h="1.5rem" size="sm" onClick={updateTodo}>Update Todo</Button>
          </ModalFooter>
        </ModalContent>
      </Modal>
    </>
  )
}
Example #11
Source File: Forget.js    From GitMarkonics with MIT License 5 votes vote down vote up
export default function Forget() {
    return (
      <>
      <Navbar />
        <div className="login">
      <div className="login__container">
        <div className="login__containerTop">
          <div className="login__img"></div>
          <p>Add a crisp to your bulky documents !!</p>
          <h4>Welcome to the website</h4>
        </div>
        <div className="login__containerBottom">
          <VStack className="input__container" w="65%" m="auto">
            <Heading
              fontSize="1.2rem"
              color="blue.500"
              fontWeight="semibold"
              py={3}
            >
              FORGET PASSWORD
            </Heading>
            <InputGroup w="95%" borderRadius="full" bgColor="gray.200">
              <InputLeftElement
                margin="0 20px"
                pointerEvents="none"
                children={
                  <RiAccountPinBoxFill color="#C6C6E8" fontSize="2.1rem" />
                }
              />
              <Input  required
                borderRadius="full"
                type="tel"
                placeholder="Email Address"
                paddingLeft="60px"
              />
            </InputGroup>
            <InputGroup
              className="login__input"
              w="95%"
              borderRadius="full"
              bgColor="gray.200"
            >
              <InputLeftElement
                margin="0 20px"
                pointerEvents="none"
                children={
                  <RiLockPasswordFill color="#C6C6E8" fontSize="2.1rem" />
                }
              />
              <Input
                type="tel" required
                borderRadius="full"
                placeholder="Password"
                paddingLeft="60px"
              />
            </InputGroup>
            <HStack className="login__btn" alignSelf="flex-end">
              <Button
                colorScheme="pink"
                px="6"
                size="sm"
                fontWeight="bold"
                className="loginBtn"
              >
                SUBMIT
              </Button>
              <Link  fontSize="sm" textDecoration="underline" color="blue">
                <a href="/login" >Remember?</a>
              </Link>
            </HStack>
          </VStack>
        </div>
      </div>
    </div>
    </>
    )
}
Example #12
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 #13
Source File: components.js    From idena-web with MIT License 5 votes vote down vote up
export function DeleteFlipDrawer({hash, cover, onDelete, ...props}) {
  const {t} = useTranslation()
  return (
    <Drawer {...props}>
      <DrawerHeader>
        <Flex
          align="center"
          justify="center"
          bg="red.012"
          h={12}
          w={12}
          rounded="xl"
        >
          <DeleteIcon boxSize={6} color="red.500" />
        </Flex>
        <Heading fontSize="lg" fontWeight={500} color="brandGray.500" mt={4}>
          {t('Delete flip')}
        </Heading>
      </DrawerHeader>
      <DrawerBody>
        <Text color="brandGray.500" fontSize="md">
          {t('Deleted flip will be moved to the drafts.')}
        </Text>
        <FlipImage
          src={cover}
          size={160}
          objectFit="cover"
          mx="auto"
          mt={8}
          mb={38}
          rounded="lg"
        />
        <FormControl mb={6}>
          <FormLabel htmlFor="hashInput" mb={2}>
            {t('Flip hash')}
          </FormLabel>
          <Input
            id="hashInput"
            h={8}
            borderColor="gray.100"
            lineHeight={rem(18)}
            px={3}
            pt={1.5}
            pb={2}
            mb={2}
            value={hash}
            isReadOnly
            _readOnly={{
              bg: 'gray.50',
              borderColor: 'gray.100',
              color: 'muted',
            }}
          />
        </FormControl>
        <PrimaryButton
          colorScheme="red"
          display="flex"
          ml="auto"
          _hover={{
            bg: 'rgb(227 60 60)',
          }}
          onClick={onDelete}
        >
          {t('Delete')}
        </PrimaryButton>
      </DrawerBody>
    </Drawer>
  )
}
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: login.jsx    From UpStats with MIT License 4 votes vote down vote up
Login = (props) => {
  const toast = useToast();
  const login = async (email, password) => {
    try {
      const { data: jwt } = await http.post("/auth", { email, password });
      window.localStorage.setItem(tokenKey, jwt);
      window.location = "/admin";
      toast({
        title: "Success",
        description: "Redirecting...",
        status: "success",
        duration: 9000,
        isClosable: true,
      });
    } catch (ex) {
      toast({
        title: "Error",
        description: "Cannot Login to Account",
        status: "error",
        duration: 9000,
        isClosable: true,
      });
    }
  };
  useEffect(() => {
    const token = window.localStorage.getItem("token");

    if (token) {
      window.location = "/admin";
    }
  }, []);

  const formik = useFormik({
    initialValues: {
      email: "",
      password: "",
    },
    validationSchema: Yup.object({
      email: Yup.string().email().label("Email").required(),
      password: Yup.string().label("Password").required(),
    }),
    onSubmit: (values) => {
      login(values.email, values.password);

      //alert(JSON.stringify(values, null, 2));
    },
  });
  return (
    <div className="w-full max-w-sm mx-auto overflow-hidden rounded-lg">
      <div className="px-6 py-4">
        <h2 className="mt-1 text-3xl font-medium text-center">Welcome Back</h2>
        <p className="mt-1 text-center">Login to continue</p>
        <form onSubmit={formik.handleSubmit}>
          <Stack>
            <Text>Email</Text>
            <Input
              id="email"
              name="email"
              type="text"
              onChange={formik.handleChange}
              onBlur={formik.handleBlur}
              value={formik.values.email}
              placeholder="Enter here"
              isInvalid={
                formik.touched.email && formik.errors.email ? true : false
              }
            />
            {formik.touched.email && formik.errors.email ? (
              <Alert status="error">
                <AlertIcon />
                {formik.errors.email}
              </Alert>
            ) : null}
          </Stack>
          <Stack>
            <Text>Password</Text>
            <Input
              id="password"
              name="password"
              type="password"
              onChange={formik.handleChange}
              onBlur={formik.handleBlur}
              value={formik.values.password}
              placeholder="Enter here"
              isInvalid={
                formik.touched.password && formik.errors.password ? true : false
              }
            />
            {formik.touched.password && formik.errors.password ? (
              <Alert status="error">
                <AlertIcon />
                {formik.errors.password}
              </Alert>
            ) : null}
          </Stack>
          {/* Login */}
          <div className="flex items-center  mt-4">
            <button
              style={{ backgroundColor: "#3747D4" }}
              className="px-4 py-2 text-white rounded hover:bg-black focus:outline-none"
              type="submit"
            >
              Login
            </button>
          </div>
        </form>
      </div>
    </div>
  );
}
Example #16
Source File: Form.js    From web-client with Apache License 2.0 4 votes vote down vote up
VulnerabilityForm = ({
    isEditForm = false,
    vulnerability,
    vulnerabilitySetter: setVulnerability,
    onFormSubmit
}) => {
    const [initialised, setInitialised] = useState(false);
    const [projects, setProjects] = useState(null);
    const [categories, setCategories] = useState(null);
    const [subCategories, setSubCategories] = useState(null);
    const [targets, setTargets] = useState(null);
    const [useOWASP, setMetrics] = useState(false);

    useEffect(() => {
        if (initialised) return;

        Promise.all([
            secureApiFetch(`/projects`, { method: 'GET' }),
            secureApiFetch(`/vulnerabilities/categories`, { method: 'GET' }),
        ])
            .then(resp => {
                const [respA, respB] = resp;
                return Promise.all([respA.json(), respB.json()]);
            })
            .then(([projects, categories]) => {
                const defaultProjectId = projects.length ? projects[0].id : 0;
                const projectId = isEditForm ? vulnerability.project_id : defaultProjectId;
                setMetrics(isOwaspProject(projects, projectId))

                var subcategories = null;
                if (vulnerability.parent_category_id) {
                    secureApiFetch(`/vulnerabilities/categories/${vulnerability.parent_category_id}`, { method: 'GET' })
                        .then(response => response.json())
                        .then(json => {
                            subcategories = json;
                        })
                }

                secureApiFetch(`/targets?projectId=${projectId}`, { method: 'GET' })
                    .then(resp => resp.json())
                    .then(targets => {
                        unstable_batchedUpdates(() => {
                            setProjects(projects);
                            setCategories(categories);
                            setTargets(targets);
                            setVulnerability(prevVulnerability => {
                                let updatedVulnerability = prevVulnerability;
                                if (!idExists(projects, prevVulnerability.project_id)) {
                                    updatedVulnerability.project_id = defaultProjectId;
                                }
                                if ((!idExists(categories, prevVulnerability.category_id)) && (!idExists(subcategories, prevVulnerability.category_id))) {
                                    updatedVulnerability.category_id = categories[0].id;
                                }
                                if (!idExists(targets, vulnerability.target_id)) {
                                    updatedVulnerability.target_id = null;
                                }
                                return updatedVulnerability;
                            })
                            setInitialised(true);
                        });
                    })
            });
    }, [initialised, isEditForm, setProjects, setCategories, setTargets, setMetrics, setVulnerability, vulnerability.target_id, vulnerability.project_id, vulnerability.parent_category_id, subCategories, setSubCategories]);

    useEffect(() => {
        if (!initialised) return;

        if (vulnerability.parent_category_id) {
            secureApiFetch(`/vulnerabilities/categories/${vulnerability.parent_category_id}`, { method: 'GET' })
                .then(response => response.json())
                .then(json => {
                    setSubCategories(json);
                })
        }

        const projectId = vulnerability.project_id;
        secureApiFetch(`/targets?projectId=${projectId}`, { method: 'GET' })
            .then(resp => resp.json())
            .then(targets => {
                unstable_batchedUpdates(() => {
                    setTargets(targets);
                    if (isEditForm) { // Edit
                        if (!idExists(targets, vulnerability.target_id)) {
                            setVulnerability(prevVulnerability => {
                                return { ...prevVulnerability, target_id: 0 }
                            });
                        }
                    }
                });
            })
    }, [initialised, isEditForm, setTargets, setVulnerability, vulnerability.target_id, vulnerability.project_id, vulnerability.parent_category_id]);

    const idExists = (elements, id) => {
        if (!elements) return false;
        for (const el of elements) {
            if (el.id === parseInt(id)) return true;
        }
        return false;
    }

    const isOwaspProject = (elements, id) => {
        let metrics = ProjectVulnerabilityMetrics[0].id;
        for (const el of elements) {
            if (el.id === parseInt(id)) {
                metrics = el.vulnerability_metrics;
            }
        }
        return (ProjectVulnerabilityMetrics[1].id === metrics);
    }

    const onFormChange = ev => {
        const target = ev.target;
        const name = target.name;
        let value = target.type === 'checkbox' ? target.checked : target.value;

        if ('tags' === name) {
            value = JSON.stringify(value.split(','));
        }

        if ('category_id' === name) {
            if (value !== '(none)') {
                secureApiFetch(`/vulnerabilities/categories/${value}`, { method: 'GET' })
                    .then(response => response.json())
                    .then(json => {
                        setSubCategories(json);
                    })
                setVulnerability({ ...vulnerability, 'parent_category_id': value, [name]: value });
            } else {
                setVulnerability({ ...vulnerability, 'category_id': null });
            }
        } else if ('subcategory_id' === name) {
            setVulnerability({ ...vulnerability, 'category_id': value });
        } else {
            setVulnerability({ ...vulnerability, [name]: value });
        }
    };

    return <form onSubmit={onFormSubmit} className="crud">
        <Accordion defaultIndex={0} allowToggle allowMultiple>
            <AccordionItem index={0}>
                <h2>
                    <AccordionButton>
                        <Box flex="1" textAlign="left">
                            Basic information
                        </Box>
                        <AccordionIcon />
                    </AccordionButton>
                </h2>
                <AccordionPanel pb={4}>
                    <label>Properties
                        <div>
                            <Checkbox name="is_template" onChange={onFormChange} isChecked={vulnerability.is_template}>Is template</Checkbox>
                        </div>
                    </label>
                    <label>External ID
                        <Input type="text" name="external_id" value={vulnerability.external_id || ""} onChange={onFormChange} />
                    </label>
                    <label>Summary
                        <Input type="text" name="summary" value={vulnerability.summary || ""} onChange={onFormChange} required autoFocus />
                    </label>
                    <label>Description
                        <MarkdownEditor name="description" value={vulnerability.description || ""} onChange={onFormChange} />
                    </label>
                    <label>External references
                        <MarkdownEditor name="external_refs" value={vulnerability.external_refs || ""} onChange={onFormChange} />
                    </label>
                    <label>Category
                        <Select name="category_id" value={vulnerability.parent_category_id || ""} onChange={onFormChange} required>
                            <option>(none)</option>
                            {categories && categories.map(cat =>
                                <option key={cat.id} value={cat.id}>{cat.name}</option>
                            )}
                        </Select>
                    </label>
                    <label>Subcategory
                        <Select name="subcategory_id" value={vulnerability.category_id || ""} onChange={onFormChange} required>
                            <option>(none)</option>
                            {subCategories && subCategories.map(subcat =>
                                <option key={subcat.id} value={subcat.id}>{subcat.name}</option>
                            )}
                        </Select>
                    </label>
                    <FormControl id="visibility" isRequired>
                        <FormLabel>Visibility</FormLabel>
                        <Select name="visibility" value={vulnerability.visibility || ""} onChange={onFormChange}>
                            <option value="public">Public</option>
                            <option value="private">Private</option>
                        </Select>
                        <FormHelperText>Private makes this vulnerability not visible to the client.</FormHelperText>
                    </FormControl>
                    <label>Risk
                        <Select name="risk" value={vulnerability.risk || ""} onChange={onFormChange} required>
                            {Risks.map(risk =>
                                <option key={risk.id} value={risk.id}>{risk.name}</option>
                            )}
                        </Select>
                    </label>
                    <label>Tags
                        <Input type="text" name="tags" onChange={onFormChange} value={vulnerability.tags ? JSON.parse(vulnerability.tags).join(',') : ''} />
                    </label>
                    <label>Proof of concept
                        <MarkdownEditor name="proof_of_concept" value={vulnerability.proof_of_concept || ""} onChange={onFormChange} />
                    </label>
                    <label>Impact
                        <MarkdownEditor name="impact" value={vulnerability.impact || ""} onChange={onFormChange} />
                    </label>
                    {
                        !useOWASP && <>
                            <label>CVSS score
                                <Input type="number" step="0.1" min="0" max="10" name="cvss_score" value={vulnerability.cvss_score || ""}
                                    onChange={onFormChange} />
                            </label>
                            <label><span><CvssAbbr /> vector</span>
                                <Input type="text" name="cvss_vector" value={vulnerability.cvss_vector || ""} onChange={onFormChange} placeholder="eg: AV:N/AC:L/Au:S/C:P/I:P/A:N" />
                            </label>
                        </>
                    }
                </AccordionPanel>
            </AccordionItem>
            {useOWASP &&
                <AccordionItem>
                    <h2>
                        <AccordionButton>
                            <Box flex="1" textAlign="left">
                                Owasp Risk Rating calculator
                            </Box>
                            <AccordionIcon />
                        </AccordionButton>
                    </h2>
                    <AccordionPanel pb={4}>
                        <label>Owasp Risk Rating</label>
                        <OwaspRR vulnerability={vulnerability} vulnerabilitySetter={setVulnerability} />
                    </AccordionPanel>
                </AccordionItem>
            }
            <AccordionItem>
                <h2>
                    <AccordionButton>
                        <Box flex="1" textAlign="left">
                            Remediation
                        </Box>
                        <AccordionIcon />
                    </AccordionButton>
                </h2>
                <AccordionPanel pb={4}>

                    <label>Remediation instructions
                        <MarkdownEditor name="remediation" value={vulnerability.remediation || ""} onChange={onFormChange} />
                    </label>
                    <label>Remediation complexity
                        <Select name="remediation_complexity" value={vulnerability.remediation_complexity || ""} onChange={onFormChange} required>
                            {RemediationComplexity.map(complexity =>
                                <option key={complexity.id} value={complexity.id}>{complexity.name}</option>
                            )}
                        </Select>
                    </label>
                    <label>Remediation priority
                        <Select name="remediation_priority" value={vulnerability.remediation_priority || ""} onChange={onFormChange} required>
                            {RemediationPriority.map(priority =>
                                <option key={priority.id} value={priority.id}>{priority.name}</option>
                            )}
                        </Select>
                    </label>
                </AccordionPanel>
            </AccordionItem>

            {
                !vulnerability.is_template && <AccordionItem>
                    <h2>
                        <AccordionButton>
                            <Box flex="1" textAlign="left">
                                Relations
                            </Box>
                            <AccordionIcon />
                        </AccordionButton>
                    </h2>
                    <AccordionPanel pb={4}>

                        <label>Project
                            <Select name="project_id" value={vulnerability.project_id || ""} onChange={onFormChange} required>
                                {projects && projects.map((project, index) =>
                                    <option key={index} value={project.id}>{project.name}</option>
                                )}
                            </Select>
                        </label>

                        <label>Affected target
                            <Select name="target_id" value={vulnerability.target_id || ""} onChange={onFormChange}>
                                <option value="0">(none)</option>
                                {targets && targets.map((target, index) =>
                                    <option key={index} value={target.id}>{target.name}</option>
                                )}
                            </Select>
                        </label>
                    </AccordionPanel>
                </AccordionItem>
            }
        </Accordion>

        <Primary type="submit">{isEditForm ? "Save" : "Add"}</Primary>
    </form >
}
Example #17
Source File: index.jsx    From UpStats with MIT License 4 votes vote down vote up
export default function Dashboard() {
  const api = create({
    baseURL: "/api",
  });

  const toast = useToast();

  const router = useRouter();
  const [systems, setSystems] = useState([]);
  const [isLoggedIn, setIsLoggedIn] = useState(false);
  const [mailing, setMailing] = useState(false);

  const [currentEditSystem, setCurrentEditSystem] = useState({
    name: "",
    url: "",
  });
  const [subsCount, setSubsCount] = useState(0);
  const loadSystems = async () => {
    try {
      const { data } = await http.get("/systems");
      setSystems(data);
    } catch (e) {
      toast({
        title: "Error",
        description: "Error Loading Systems",
        status: "error",
        duration: 9000,
        isClosable: true,
      });
    }
  };
  const loadConfig = async () => {
    try {
      const { data } = await http.get("/config");
      setMailing(data.mailing);
    } catch (e) {
      console.log("Error Loading Config");
    }
  };
  const loadCount = async () => {
    try {
      const { data } = await http.get("/subs");

      setSubsCount(data.length);
    } catch (e) {
      toast({
        title: "Error",
        description: "Error Loading Subs Count",
        status: "error",
        duration: 9000,
        isClosable: true,
      });
    }
  };
  useEffect(() => {
    const token = window.localStorage.getItem("token");
    http.setJwt(token);

    if (!token) {
      setIsLoggedIn(false);
      toast({
        title: "Error",
        description: "Redirecting to Login Page",
        status: "warning",
        duration: 9000,
        isClosable: true,
      });
      router.push("/login");
    } else setIsLoggedIn(true);
  }, []);
  useEffect(() => {
    loadSystems();
  }, []);

  useEffect(() => {
    loadCount();
  }, []);
  useEffect(() => {
    loadConfig();
  }, []);
  const handleDelete = async (system) => {
    const originalSystems = systems;
    const newSystems = originalSystems.filter((s) => s._id !== system._id);

    setSystems(newSystems);
    try {
      await http.delete(`/systems/${system._id}`);
    } catch (ex) {
      if (ex.response && ex.response.status === 404)
        toast({
          title: "Error",
          description: "System May be Already Deleted",
          status: "error",
          duration: 9000,
          isClosable: true,
        });
      setSystems(originalSystems);
    }
  };
  const handleAdd = async (system) => {
    try {
      const { data } = await api.post("/systems", system, {
        headers: localStorage.getItem("token"),
      });
      setSystems([...systems, data]);
    } catch (ex) {
      toast({
        title: "Error",
        description: "Submit Unsuccessful",
        status: "error",
        duration: 9000,
        isClosable: true,
      });
    }
  };

  const formik = useFormik({
    initialValues: {
      name: "",
      url: "",
      type: "web",
    },
    validationSchema: Yup.object({
      name: Yup.string()
        .max(15, "Must be 15 characters or less")
        .required("Required"),
      url: Yup.string().required("Required"),
      type: Yup.string(),
    }),
    onSubmit: (values) => {
      handleAdd(values);
      //alert(JSON.stringify(values, null, 2));
    },
  });
  const handleEdit = async () => {
    const originalSystems = systems;
    let newSystems = [...systems];
    const idx = newSystems.findIndex(
      (sys) => sys._id === currentEditSystem._id
    );
    newSystems[idx] = { ...currentEditSystem };

    setSystems(newSystems);
    try {
      await http.put(`/systems/${currentEditSystem._id}`, {
        name: currentEditSystem.name,
        url: currentEditSystem.url,
        type: currentEditSystem.type,
      });
      setCurrentEditSystem({ name: "", url: "" });
    } catch (ex) {
      toast({
        title: "Error",
        description: "Error Updating The System",
        status: "error",
        duration: 9000,
        isClosable: true,
      });
      setSystems(originalSystems);
      setCurrentEditSystem({ name: "", url: "" });
    }
  };
  const handleChangeConfig = async () => {
    try {
      await http.put(`/config`, {
        mailing: mailing,
      });
    } catch (ex) {
      toast({
        title: "Error",
        description: "Error Updating The Config",
        status: "error",
        duration: 9000,
        isClosable: true,
      });
    }
  };
  return (
    <FormikProvider value={formik}>
      <>
        <Layout>
          {isLoggedIn ? (
            <>
              <div className=" mt-12  mx-auto">
                <div>
                  <div className="m-auto p-4 md:w-1/4 sm:w-1/2 w-full">
                    <div className="p-12 py-6 rounded-lg">
                      <svg
                        fill="none"
                        stroke="currentColor"
                        strokeLinecap="round"
                        strokeLinejoin="round"
                        strokeWidth={2}
                        className="w-12 h-12 inline-block users-status"
                        viewBox="0 0 24 24"
                      >
                        <path d="M17 21v-2a4 4 0 00-4-4H5a4 4 0 00-4 4v2" />
                        <circle cx={9} cy={7} r={4} />
                        <path d="M23 21v-2a4 4 0 00-3-3.87m-4-12a4 4 0 010 7.75" />
                      </svg>
                      <h2 className="title-font font-medium text-3xl">
                        {subsCount}
                      </h2>
                      <p className="leading-relaxed ">Users Subscribed</p>
                    </div>
                  </div>
                </div>
              </div>
              {/* CRUD Status List */}
              <div className="w-full max-w-sm overflow-hidden rounded-lg items-center mx-auto">
                <h3 className="text-2xl font-black text-black">
                  Add New System
                </h3>
                <form onSubmit={formik.handleSubmit} className="p-3">
                  <Stack>
                    <Text>System Title</Text>
                    <Input
                      id="name"
                      name="name"
                      type="text"
                      onChange={formik.handleChange}
                      onBlur={formik.handleBlur}
                      value={formik.values.name}
                      placeholder="Enter here"
                      isInvalid={
                        formik.touched.name && formik.errors.name ? true : false
                      }
                    />
                    {formik.touched.name && formik.errors.name ? (
                      <Alert status="error">
                        <AlertIcon />
                        {formik.errors.name}
                      </Alert>
                    ) : null}
                  </Stack>
                  <Stack mt={2}>
                    <Text>System URL</Text>
                    <Input
                      placeholder="Enter here"
                      id="url"
                      name="url"
                      type="text"
                      onChange={formik.handleChange}
                      onBlur={formik.handleBlur}
                      value={formik.values.url}
                      isInvalid={
                        formik.touched.url && formik.errors.url ? true : false
                      }
                    />
                    {formik.touched.url && formik.errors.url ? (
                      <Alert status="error">
                        <AlertIcon />
                        {formik.errors.url}
                      </Alert>
                    ) : null}
                  </Stack>
                  {/* Select System Type */}
                  <RadioGroup>
                    <Stack mt={5}>
                      <Field as={Radio} type="radio" name="type" value="web">
                        Web
                      </Field>
                      <Field
                        as={Radio}
                        type="radio"
                        name="type"
                        value="telegram"
                      >
                        Telegram Bot
                      </Field>
                    </Stack>
                  </RadioGroup>
                  {/* Add */}
                  <div className="mt-4">
                    <button
                      style={{ backgroundColor: "#3747D4" }}
                      className="px-4 py-2 text-white rounded hover:bg-black focus:outline-none"
                      type="submit"
                    >
                      Add
                    </button>
                  </div>
                </form>
                {/* Status Page List */}
                {/* Show Sites here */}
                {systems.map((system) => (
                  <div key={system._id} className="status-items-manage">
                    <div className="items">
                      <span className="site-title">{system?.name}</span>
                      <div className="i">
                        <EditIcon
                          mr="2"
                          onClick={() => {
                            setCurrentEditSystem(system);
                          }}
                        />
                        <DeleteIcon
                          color="red"
                          m="2"
                          onClick={() => {
                            handleDelete(system);
                          }}
                        />
                      </div>
                    </div>
                  </div>
                ))}
                {/* End */}
                {currentEditSystem.name ? (
                  <div className="mt-4">
                    <Stack>
                      <h3 className="text-2xl font-black text-black">
                        Edit System
                      </h3>
                      <Stack>
                        <Text>System Title</Text>
                        <Input
                          id="name"
                          name="name"
                          type="text"
                          value={currentEditSystem.name}
                          onChange={(e) => {
                            setCurrentEditSystem({
                              ...currentEditSystem,
                              name: e.target.value,
                            });
                          }}
                          placeholder="Enter here"
                        />
                      </Stack>
                      <Stack mt={2}>
                        <Text>System URL</Text>
                        <Input
                          placeholder="Enter here"
                          id="url"
                          name="url"
                          type="text"
                          value={currentEditSystem.url}
                          onChange={(e) =>
                            setCurrentEditSystem({
                              ...currentEditSystem,
                              url: e.target.value,
                            })
                          }
                        />
                      </Stack>
                    </Stack>
                    {/* Add */}
                    <div className="mt-4">
                      <button
                        onClick={handleEdit}
                        style={{ backgroundColor: "#3747D4" }}
                        className="px-4 py-2 text-white rounded hover:bg-black focus:outline-none"
                      >
                        Done
                      </button>
                    </div>
                  </div>
                ) : (
                  ""
                )}
                <Stack mt={12}>
                  <h3 className="text-xl font-black text-bold">Configs</h3>
                  <p className="text-md font-black text-bold">Mailing</p>
                  <Switch
                    size="lg"
                    isChecked={mailing}
                    onChange={(e) => setMailing(e.target.checked)}
                  />
                  <div className="mt-4">
                    <button
                      onClick={handleChangeConfig}
                      style={{ backgroundColor: "#3747D4" }}
                      className="px-4 py-2 text-white rounded hover:bg-black focus:outline-none"
                    >
                      Done
                    </button>
                  </div>
                </Stack>
              </div>
            </>
          ) : (
            ""
          )}

          {/* Total No. of Users Subscribed */}
        </Layout>
      </>
    </FormikProvider>
  );
}
Example #18
Source File: Dashboard.js    From MeowForm with MIT License 4 votes vote down vote up
Dashboard = () => {
	const { isLoading, user } = useAuth0();
	const [check] = useMediaQuery("(min-width: 1025px)");
	const { isOpen, onOpen, onClose } = useDisclosure();
	const [formName, setFormName] = React.useState();
	let userEmail = user.email;
	let apiKey = process.env.REACT_APP_APIKEY;
	let apiUrl = process.env.REACT_APP_HOSTURL;
	const [data, setData] = React.useState();
	const getData = async () => {
		let temp = await axios.get(apiUrl + "user/" + userEmail + "&" + apiKey);
		setData(temp.data[0]);
		console.log(data);
	};
	useEffect(() => {
		getData();
		if (data === undefined) {
			setTimeout(() => getData(), 2500);
		}
	}, []);
	let responses = 0;
	if (data) {
		for (let i = 0; i < data.forms.length; i++) {
			responses += data.forms[i].formData.length;
		}
	}

	const postApiData = async () => {
		let temp = await axios.post(apiUrl + "addForm/" + apiKey, {
			email: user.email,
			formName: formName,
			url: "",
		});
		getData();
	};
	const addNewForm = () => {
		if (formName === "") {
			toast.error("Form is empty?");
		} else {
			//  console.log(data.forms[0].formName);
			let isCopy = false;
			for (let i = 0; i < data.forms.length; i++) {
				if (data.forms[i].formName === formName) {
					isCopy = true;
				}
			}
			if (isCopy) {
				toast.error("form with such name already exits ");
			} else {
				postApiData();
				setTimeout(() => getData(), 2000);
				onClose();
				setTimeout(
					() => toast.success("Form Have beeen added ?"),
					2000
				);
			}
		}
	};

	return (
		<Box backgroundColor='whiteAlpha.100'>
			<Box
				padding='6'
				boxShadow='2xl'
				align='center'
				margin='2%'
				borderRadius={check ? "full" : "0 "}>
				<Flex align='center' flexDirection={check ? "row" : "column"}>
					<Flex>
						<Image src={user.picture} borderRadius='full' />
						<Text
							mt='10%'
							ml='20px'
							bgGradient='linear(to-l, #ec9f05 ,#ff4e00)'
							bgClip='text'
							fontSize={check ? "3xl" : "xl"}>
							{user.name}
						</Text>
					</Flex>

					<Flex align='center' ml={check ? "40%" : "10%"}>
						<Box>
							<Text
								bgGradient='linear(to-l, #ec9f05 ,#ff4e00)'
								bgClip='text'
								fontSize='3xl'>
								{data ? (
									responses
								) : (
									<SkeletonText></SkeletonText>
								)}
							</Text>
							<Text>Responses</Text>
						</Box>
						<Box ml='50%'>
							<Text
								bgGradient='linear(to-l, #ec9f05 ,#ff4e00)'
								bgClip='text'
								fontSize='3xl'>
								{data ? (
									data.forms.length
								) : (
									<SkeletonText></SkeletonText>
								)}
							</Text>

							<Text>Forms</Text>
						</Box>
					</Flex>
				</Flex>
			</Box>

			<Box
				padding='6'
				boxShadow='xl'
				margin='2%'
				borderRadius={check ? "25px" : "0 "}>
				<Flex justifyContent='space-between'>
					<Text
						margin='5%'
						bgGradient='linear(to-l, #ec9f05 ,#ff4e00)'
						bgClip='text'
						fontSize='3xl'>
						Forms
					</Text>
					<Button margin='5%' colorScheme='orange' onClick={onOpen}>
						New form
					</Button>
				</Flex>
				<Divider margin='2%' colorScheme='blackAlpha'></Divider>
				{data ? (
					data.forms.map((x) => (
						<FormCard
							formName={x.formName}
							responses={x.formData.length}
							formData={x.formData}
							redirectUrl={x.redirectUrl}
							email={userEmail}></FormCard>
					))
				) : (
					<>
						<SkeletonText mt='3' noOfLines={1}></SkeletonText>
						<SkeletonText mt='3' noOfLines={1}></SkeletonText>
					</>
				)}

				{data && data.forms.length === 0 ? (
					<>
						<Image
							src='https://res.cloudinary.com/dd0mtkqbr/image/upload/v1629867315/kitekat-3_dlccdn.png'
							width='25%'
							height='25%'
							ml='38%'
						/>
						<Text align='center'>
							You haven't created a form Yet{" "}
						</Text>
					</>
				) : (
					<> </>
				)}
			</Box>
			<Drawer
				onClose={onClose}
				isOpen={isOpen}
				size={check ? "xs" : "xs"}>
				<DrawerOverlay />
				<DrawerContent>
					<DrawerHeader align='center'>
						<Text
							margin='1%'
							fontWeight='extraBold'
							fontSize='3xl'
							bgGradient='linear(to-l, #ec9f05 ,#ff4e00)'
							bgClip='text'>
							Add Form
						</Text>
						<Image src='https://res.cloudinary.com/dd0mtkqbr/image/upload/v1629884425/kitekat-17_ipr2uy.png' />
						<Text></Text>
					</DrawerHeader>
					<DrawerBody>
						<Box>
							<Flex>
								<Input
									onChange={(e) =>
										setFormName(e.target.value)
									}
									placeholder='Form Name'
								/>
								<Button
									ml='0.5%'
									colorScheme='orange'
									onClick={addNewForm}>
									{" "}
									&gt;{" "}
								</Button>
							</Flex>
						</Box>
						<Box></Box>
					</DrawerBody>
				</DrawerContent>
			</Drawer>

			<Toaster />
		</Box>
	);
}
Example #19
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 #20
Source File: showreel.js    From react-table-library with MIT License 4 votes vote down vote up
Component = () => {
  const [data, setData] = React.useState({ nodes });

  //* Theme *//

  const chakraTheme = getTheme({
    ...DEFAULT_OPTIONS,
    striped: true,
  });
  const customTheme = {
    Table: `
      --data-table-library_grid-template-columns:  64px repeat(5, minmax(0, 1fr));

      margin: 16px 0px;
    `,
  };
  const theme = useTheme([chakraTheme, customTheme]);

  //* Resize *//

  const resize = { resizerHighlight: '#dee2e6' };

  //* Pagination *//

  const pagination = usePagination(data, {
    state: {
      page: 0,
      size: 4,
    },
    onChange: onPaginationChange,
  });

  function onPaginationChange(action, state) {
    console.log(action, state);
  }

  //* Search *//

  const [search, setSearch] = React.useState('');

  useCustom('search', data, {
    state: { search },
    onChange: onSearchChange,
  });

  function onSearchChange(action, state) {
    console.log(action, state);
    pagination.fns.onSetPage(0);
  }

  //* Filter *//

  const [isHide, setHide] = React.useState(false);

  useCustom('filter', data, {
    state: { isHide },
    onChange: onFilterChange,
  });

  function onFilterChange(action, state) {
    console.log(action, state);
    pagination.fns.onSetPage(0);
  }

  //* Select *//

  const select = useRowSelect(data, {
    onChange: onSelectChange,
  });

  function onSelectChange(action, state) {
    console.log(action, state);
  }

  //* Tree *//

  const tree = useTree(
    data,
    {
      onChange: onTreeChange,
    },
    {
      clickType: TreeExpandClickTypes.ButtonClick,
      treeYLevel: 1,
      treeIcon: {
        margin: '4px',
        iconDefault: null,
        iconRight: <FaChevronRight />,
        iconDown: <FaChevronDown />,
      },
    },
  );

  function onTreeChange(action, state) {
    console.log(action, state);
  }

  //* Sort *//

  const sort = useSort(
    data,
    {
      onChange: onSortChange,
    },
    {
      sortIcon: {
        iconDefault: null,
        iconUp: <FaChevronUp />,
        iconDown: <FaChevronDown />,
      },
      sortFns: {
        TASK: (array) => array.sort((a, b) => a.name.localeCompare(b.name)),
        DEADLINE: (array) => array.sort((a, b) => a.deadline - b.deadline),
        TYPE: (array) => array.sort((a, b) => a.type.localeCompare(b.type)),
        COMPLETE: (array) => array.sort((a, b) => a.isComplete - b.isComplete),
        TASKS: (array) => array.sort((a, b) => (a.nodes || []).length - (b.nodes || []).length),
      },
    },
  );

  function onSortChange(action, state) {
    console.log(action, state);
  }

  //* Drawer *//

  const [drawerId, setDrawerId] = React.useState(null);
  const [edited, setEdited] = React.useState('');

  const handleEdit = (event) => {
    setEdited(event.target.value);
  };

  const handleCancel = () => {
    setEdited('');
    setDrawerId(null);
  };

  const handleSave = () => {
    const node = findNodeById(data.nodes, drawerId);
    const editedNode = { ...node, name: edited };
    const nodes = insertNode(data.nodes, editedNode);

    setData({
      nodes,
    });

    setEdited('');
    setDrawerId(null);
  };

  //* Modal *//

  const [modalOpened, setModalOpened] = React.useState(false);

  //* Custom Modifiers *//

  let modifiedNodes = data.nodes;

  // search
  modifiedNodes = modifiedNodes.filter((node) =>
    node.name.toLowerCase().includes(search.toLowerCase()),
  );

  // filter
  modifiedNodes = isHide ? modifiedNodes.filter((node) => !node.isComplete) : modifiedNodes;

  //* Columns *//

  const COLUMNS = [
    {
      label: 'Task',
      renderCell: (item) => item.name,
      resize,
      sort: { sortKey: 'TASK' },
      select: {
        renderHeaderCellSelect: () => (
          <Checkbox
            colorScheme="teal"
            isChecked={select.state.all}
            isIndeterminate={!select.state.all && !select.state.none}
            onChange={select.fns.onToggleAll}
          />
        ),
        renderCellSelect: (item) => (
          <Checkbox
            colorScheme="teal"
            style={{ backgroundColor: '#ffffff' }}
            isChecked={select.state.ids.includes(item.id)}
            onChange={() => select.fns.onToggleById(item.id)}
          />
        ),
      },
      tree: true,
    },
    {
      label: 'Deadline',
      renderCell: (item) =>
        item.deadline.toLocaleDateString('en-US', {
          year: 'numeric',
          month: '2-digit',
          day: '2-digit',
        }),
      resize,
      sort: { sortKey: 'DEADLINE' },
    },
    { label: 'Type', renderCell: (item) => item.type, resize, sort: { sortKey: 'TYPE' } },
    {
      label: 'Complete',
      renderCell: (item) => item.isComplete.toString(),
      resize,
      sort: { sortKey: 'COMPLETE' },
    },
    {
      label: 'Tasks',
      renderCell: (item) => (
        <div style={{ display: 'flex', justifyContent: 'space-between', alignItems: 'center' }}>
          <span>{item.nodes?.length}</span>
          <IconButton
            aria-label="edit"
            icon={<FaPen />}
            size="xs"
            variant="ghost"
            colorScheme="teal"
            onClick={() => setDrawerId(item.id)}
          />
        </div>
      ),
      resize,
      sort: { sortKey: 'TASKS' },
    },
  ];

  return (
    <>
      <Modal isOpen={modalOpened} onClose={() => setModalOpened(false)}>
        <ModalOverlay />
        <ModalContent>
          <ModalHeader>Not all features included here, but we got ...</ModalHeader>
          <ModalCloseButton />
          <ModalBody>
            <div>
              <Checkbox colorScheme="teal" isChecked>
                Resize
              </Checkbox>
            </div>
            <div>
              <Checkbox colorScheme="teal" isChecked>
                Sort
              </Checkbox>
            </div>
            <div>
              <Checkbox colorScheme="teal" isChecked>
                Search
              </Checkbox>
            </div>
            <div>
              <Checkbox colorScheme="teal" isChecked>
                Filter
              </Checkbox>
            </div>
            <div>
              <Checkbox colorScheme="teal" isChecked>
                Select
              </Checkbox>
            </div>
            <div>
              <Checkbox colorScheme="teal" isChecked>
                Tree
              </Checkbox>
            </div>
            <div>
              <Checkbox colorScheme="teal" isChecked>
                Drawer on Edit
              </Checkbox>
            </div>
            <div>
              <Checkbox colorScheme="teal" isChecked>
                Pagination
              </Checkbox>
            </div>
          </ModalBody>
        </ModalContent>
      </Modal>

      {/* Form */}

      <HStack m={3}>
        <Button colorScheme="teal" onClick={() => setModalOpened(true)}>
          Features?
        </Button>

        <InputGroup>
          <InputLeftElement
            pointerEvents="none"
            children={<FaSearch style={{ color: '#4a5568' }} />}
          />
          <Input
            placeholder="Search Task"
            value={search}
            onChange={(event) => setSearch(event.target.value)}
          />
        </InputGroup>

        <Checkbox
          style={{ whiteSpace: 'nowrap' }}
          colorScheme="teal"
          isChecked={isHide}
          onChange={(event) => setHide(event.target.checked)}
        >
          Hide Complete
        </Checkbox>
      </HStack>

      {/* Table */}

      <Box p={3} borderWidth="1px" borderRadius="lg">
        <CompactTable
          columns={COLUMNS}
          data={{ ...data, nodes: modifiedNodes }}
          theme={theme}
          layout={{ custom: true }}
          select={select}
          tree={tree}
          sort={sort}
          pagination={pagination}
        />
      </Box>

      <br />
      <HStack justify="flex-end">
        <IconButton
          aria-label="previous page"
          icon={<FaChevronLeft />}
          colorScheme="teal"
          variant="ghost"
          disabled={pagination.state.page === 0}
          onClick={() => pagination.fns.onSetPage(pagination.state.page - 1)}
        />

        {pagination.state.getPages(modifiedNodes).map((_, index) => (
          <Button
            key={index}
            colorScheme="teal"
            variant={pagination.state.page === index ? 'solid' : 'ghost'}
            onClick={() => pagination.fns.onSetPage(index)}
          >
            {index + 1}
          </Button>
        ))}
        <IconButton
          aria-label="next page"
          icon={<FaChevronRight />}
          colorScheme="teal"
          variant="ghost"
          disabled={pagination.state.page + 1 === pagination.state.getTotalPages(data.nodes)}
          onClick={() => pagination.fns.onSetPage(pagination.state.page + 1)}
        />
      </HStack>

      <Drawer isOpen={drawerId} onClose={handleCancel} placement="right">
        <DrawerOverlay />
        <DrawerContent>
          <DrawerCloseButton />
          <DrawerHeader>Create your account</DrawerHeader>

          <DrawerBody>
            <Text>Name: </Text>
            <Input
              autoFocus
              value={
                edited || fromTreeToList(data.nodes).find((node) => node.id === drawerId)?.name
              }
              onChange={handleEdit}
              data-autofocus
            />
          </DrawerBody>

          <DrawerFooter>
            <Button variant="outline" mr={3} onClick={handleCancel}>
              Cancel
            </Button>
            <Button onClick={handleSave} colorScheme="teal">
              Save
            </Button>
          </DrawerFooter>
        </DrawerContent>
      </Drawer>
    </>
  );
}
Example #21
Source File: Register.js    From GitMarkonics with MIT License 4 votes vote down vote up
function Register() {
  return (
    <>
    <Navbar />
    <div className="Register">
      <div className="Register__container">
        <div className="Register__containerTop">
          <div className="Register__img"></div>
          <p>Add a crisp to your bulky documents !!</p>
          <h4>Welcome to the website</h4>
        </div>
        <div className="Register__containerBottom">
          <VStack className="input__container" w="65%" m="auto">
            <Heading
              fontSize="1.2rem"
              color="blue.500"
              fontWeight="semibold"
              py={3}
            >
              Register HERE
            </Heading>
            <InputGroup w="95%" borderRadius="full">
              <Input
                borderRadius="full"
                type="tel"
                placeholder="First Name"
                bgColor="gray.200"
              />
              <Input
                borderRadius="full"
                type="tel"
                placeholder="Last Name"
                bgColor="gray.200"
                marginLeft="4px"
              />
            </InputGroup>
            <InputGroup w="95%" borderRadius="full" bgColor="gray.200">
              <InputLeftElement
                margin="0 20px"
                pointerEvents="none"
                children={
                  <BsFillPersonFill color="#C6C6E8" fontSize="1.6rem" />
                }
              />
              <Input
                borderRadius="full"
                type="tel"
                placeholder="Username"
                paddingLeft="60px"
              />
            </InputGroup>
            <InputGroup
              className="Register__input"
              w="95%"
              borderRadius="full"
              bgColor="gray.200"
            >
              <InputLeftElement
                margin="0 20px"
                pointerEvents="none"
                children={
                  <BsFillLockFill color="#C6C6E8" fontSize="1.4rem" />
                }
              />
              <Input
                type="password"
                borderRadius="full"
                placeholder="Password"
                paddingLeft="60px"
              />
            </InputGroup>
            <InputGroup
              className="Register__input"
              w="95%"
              borderRadius="full"
              bgColor="gray.200"
            >
              <InputLeftElement
                margin="0 20px"
                pointerEvents="none"
                children={
                  <BsFillLockFill color="#C6C6E8" fontSize="1.4rem" />
                }
              />
              <Input
                type="password"
                borderRadius="full"
                placeholder=" Confirm Password"
                paddingLeft="60px"
              />
            </InputGroup>
            <Link  fontSize="sm" textDecoration="underline" color="blue">
                <a href="/login" >Have Account?</a>
              </Link>
            <HStack className="Register__btn" alignSelf="flex-end">
              <Button
                colorScheme="pink"
                px="6"
                size="sm"
                fontWeight="bold"
                className="RegisterBtn"
              >
                Register
              </Button>
            </HStack>
          </VStack>
        </div>
      </div>
    </div>
    </>
  );
}
Example #22
Source File: BuilderProfileCard.jsx    From scaffold-directory with MIT License 4 votes vote down vote up
BuilderProfileCard = ({ builder, mainnetProvider, isMyProfile, userProvider, fetchBuilder, userRole }) => {
  const address = useUserAddress(userProvider);
  const ens = useDisplayAddress(mainnetProvider, builder?.id);
  const [updatedSocials, setUpdatedSocials] = useState({});
  const [isUpdatingReachedOutFlag, setIsUpdatingReachedOutFlag] = useState(false);
  const [isUpdatingSocials, setIsUpdatingSocials] = useState(false);
  const { isOpen, onOpen, onClose } = useDisclosure();
  const { hasCopied, onCopy } = useClipboard(builder?.id);
  const { borderColor, secondaryFontColor } = useCustomColorModes();
  const shortAddress = ellipsizedAddress(builder?.id);
  const hasEns = ens !== shortAddress;

  const toast = useToast({ position: "top", isClosable: true });
  const toastVariant = useColorModeValue("subtle", "solid");

  const joinedDate = new Date(builder?.creationTimestamp);
  const joinedDateDisplay = joinedDate.toLocaleString("default", { month: "long" }) + " " + joinedDate.getFullYear();

  // INFO: conditional chaining and coalescing didn't work when also checking the length
  const hasProfileLinks = builder?.socialLinks ? Object.keys(builder.socialLinks).length !== 0 : false;

  const isAdmin = userRole === USER_ROLES.admin;

  useEffect(() => {
    if (builder) {
      setUpdatedSocials(builder.socialLinks ?? {});
    }
  }, [builder]);

  const handleUpdateSocials = async () => {
    setIsUpdatingSocials(true);

    // Avoid sending socials with empty strings.
    const socialLinkCleaned = Object.fromEntries(Object.entries(updatedSocials).filter(([_, value]) => !!value));

    const invalidSocials = validateSocials(socialLinkCleaned);
    if (invalidSocials.length !== 0) {
      toast({
        description: `The usernames for the following socials are not correct: ${invalidSocials
          .map(([social]) => social)
          .join(", ")}`,
        status: "error",
        variant: toastVariant,
      });
      setIsUpdatingSocials(false);
      return;
    }

    let signMessage;
    try {
      signMessage = await getUpdateSocialsSignMessage(address);
    } catch (error) {
      toast({
        description: " Sorry, the server is overloaded. ???",
        status: "error",
        variant: toastVariant,
      });
      setIsUpdatingSocials(false);
      return;
    }

    let signature;
    try {
      signature = await userProvider.send("personal_sign", [signMessage, address]);
    } catch (error) {
      toast({
        description: "Couldn't get a signature from the Wallet",
        status: "error",
        variant: toastVariant,
      });
      setIsUpdatingSocials(false);
      return;
    }

    try {
      await postUpdateSocials(address, signature, socialLinkCleaned);
    } catch (error) {
      if (error.status === 401) {
        toast({
          status: "error",
          description: "Access error",
          variant: toastVariant,
        });
        setIsUpdatingSocials(false);
        return;
      }
      toast({
        status: "error",
        description: "Can't update your socials. Please try again.",
        variant: toastVariant,
      });
      setIsUpdatingSocials(false);
      return;
    }

    toast({
      description: "Your social links have been updated",
      status: "success",
      variant: toastVariant,
    });
    fetchBuilder();
    setIsUpdatingSocials(false);
    onClose();
  };

  const handleUpdateReachedOutFlag = async reachedOut => {
    setIsUpdatingReachedOutFlag(true);

    let signMessage;
    try {
      signMessage = await getUpdateReachedOutFlagSignMessage(builder.id, reachedOut);
    } catch (error) {
      toast({
        description: " Sorry, the server is overloaded. ???",
        status: "error",
        variant: toastVariant,
      });
      setIsUpdatingReachedOutFlag(false);
      return;
    }

    let signature;
    try {
      signature = await userProvider.send("personal_sign", [signMessage, address]);
    } catch (error) {
      toast({
        description: "Couldn't get a signature from the Wallet",
        status: "error",
        variant: toastVariant,
      });
      setIsUpdatingReachedOutFlag(false);
      return;
    }

    try {
      await postUpdateReachedOutFlag(address, builder.id, reachedOut, signature);
    } catch (error) {
      if (error.status === 401) {
        toast({
          status: "error",
          description: "Access error",
          variant: toastVariant,
        });
        setIsUpdatingReachedOutFlag(false);
        return;
      }
      toast({
        status: "error",
        description: "Can't update the reached out flag. Please try again.",
        variant: toastVariant,
      });
      setIsUpdatingReachedOutFlag(false);
      return;
    }

    toast({
      description: 'Updated "reached out" flag successfully',
      status: "success",
      variant: toastVariant,
    });
    fetchBuilder();
    setIsUpdatingReachedOutFlag(false);
  };

  return (
    <>
      <BuilderProfileCardSkeleton isLoaded={!!builder}>
        {() => (
          /* delay execution */
          <Flex
            borderRadius="lg"
            borderColor={borderColor}
            borderWidth={1}
            justify={{ base: "space-around", xl: "center" }}
            direction={{ base: "row", xl: "column" }}
            p={4}
            pb={6}
            maxW={{ base: "full", lg: "50%", xl: 60 }}
            margin="auto"
          >
            <Link as={RouteLink} to={`/builders/${builder.id}`}>
              <QRPunkBlockie
                withQr={false}
                address={builder.id?.toLowerCase()}
                w={52}
                borderRadius="lg"
                margin="auto"
              />
            </Link>
            <Flex alignContent="center" direction="column" mt={4}>
              {hasEns ? (
                <>
                  <Text fontSize="2xl" fontWeight="bold" textAlign="center">
                    {ens}
                  </Text>
                  <Text textAlign="center" mb={4} color={secondaryFontColor}>
                    {shortAddress}{" "}
                    <Tooltip label={hasCopied ? "Copied!" : "Copy"} closeOnClick={false}>
                      <CopyIcon cursor="pointer" onClick={onCopy} />
                    </Tooltip>
                  </Text>
                </>
              ) : (
                <Text fontSize="2xl" fontWeight="bold" textAlign="center" mb={8}>
                  {shortAddress}{" "}
                  <Tooltip label={hasCopied ? "Copied!" : "Copy"} closeOnClick={false}>
                    <CopyIcon cursor="pointer" onClick={onCopy} />
                  </Tooltip>
                </Text>
              )}
              {isAdmin && (
                <Center mb={4}>
                  {builder.reachedOut ? (
                    <Badge variant="outline" colorScheme="green" alignSelf="center">
                      Reached Out
                    </Badge>
                  ) : (
                    <Button
                      colorScheme="green"
                      size="xs"
                      onClick={() => handleUpdateReachedOutFlag(true)}
                      isLoading={isUpdatingReachedOutFlag}
                      alignSelf="center"
                    >
                      Mark as reached out
                    </Button>
                  )}
                </Center>
              )}
              <Divider mb={6} />
              {hasProfileLinks ? (
                <Flex mb={4} justifyContent="space-evenly" alignItems="center">
                  {Object.entries(builder.socialLinks)
                    .sort(bySocialWeight)
                    .map(([socialId, socialValue]) => (
                      <SocialLink id={socialId} value={socialValue} />
                    ))}
                </Flex>
              ) : (
                isMyProfile && (
                  <Alert mb={3} status="warning">
                    <Text style={{ fontSize: 11 }}>
                      You haven't set your socials{" "}
                      <Tooltip label="It's our way of reaching out to you. We could sponsor you an ENS, offer to be part of a build or set up an ETH stream for you.">
                        <QuestionOutlineIcon />
                      </Tooltip>
                    </Text>
                  </Alert>
                )
              )}
              {isMyProfile && (
                <Button mb={3} size="xs" variant="outline" onClick={onOpen}>
                  Update socials
                </Button>
              )}
              <Text textAlign="center" color={secondaryFontColor}>
                Joined {joinedDateDisplay}
              </Text>
            </Flex>
          </Flex>
        )}
      </BuilderProfileCardSkeleton>
      <Modal isOpen={isOpen} onClose={onClose}>
        <ModalOverlay />
        <ModalContent>
          <ModalHeader>Update your socials</ModalHeader>
          <ModalCloseButton />
          <ModalBody p={6}>
            {Object.entries(socials).map(([socialId, socialData]) => (
              <FormControl id="socialId" key={socialId} mb={3}>
                <FormLabel htmlFor={socialId} mb={0}>
                  <strong>{socialData.label}:</strong>
                </FormLabel>
                <Input
                  type="text"
                  name={socialId}
                  value={updatedSocials[socialId] ?? ""}
                  placeholder={socialData.placeholder}
                  onChange={e => {
                    const value = e.target.value;
                    setUpdatedSocials(prevSocials => ({
                      ...prevSocials,
                      [socialId]: value,
                    }));
                  }}
                />
              </FormControl>
            ))}
            <Button colorScheme="blue" onClick={handleUpdateSocials} isLoading={isUpdatingSocials} isFullWidth mt={4}>
              Update
            </Button>
          </ModalBody>
        </ModalContent>
      </Modal>
    </>
  );
}
Example #23
Source File: register.jsx    From UpStats with MIT License 4 votes vote down vote up
Register = (props) => {
  const toast = useToast();
  const register = async (creds) => {
    try {
      const { data: jwt } = await http.post("/users/create", { ...creds });
      window.localStorage.setItem(tokenKey, jwt);
      window.location = "/admin";
      toast({
        title: "Success",
        description: "Redirecting...",
        status: "success",
        duration: 9000,
        isClosable: true,
      });
    } catch (ex) {
      toast({
        title: "Error",
        description: "Cannot Login to Account",
        status: "error",
        duration: 9000,
        isClosable: true,
      });
    }
  };
  useEffect(() => {
    const token = window.localStorage.getItem("token");

    if (token) {
      window.location = "/admin";
    }
  }, []);

  const formik = useFormik({
    initialValues: {
      name: "",
      email: "",
      password: "",
    },
    validationSchema: Yup.object({
      name: Yup.string().label("Name").required(),
      email: Yup.string().email().label("Email").required(),
      password: Yup.string().label("Password").required(),
    }),
    onSubmit: (values) => {
      register(values);

      //alert(JSON.stringify(values, null, 2));
    },
  });
  return (
    <div className="w-full max-w-sm mx-auto overflow-hidden rounded-lg">
      <div className="px-6 py-4">
        <h2 className="mt-1 text-3xl font-medium text-center">Welcome Back</h2>
        <p className="mt-1 text-center">Login to continue</p>
        <form onSubmit={formik.handleSubmit}>
          <Stack>
            <Text>Name</Text>
            <Input
              id="name"
              name="name"
              type="text"
              onChange={formik.handleChange}
              onBlur={formik.handleBlur}
              value={formik.values.name}
              placeholder="Enter here"
              isInvalid={
                formik.touched.name && formik.errors.name ? true : false
              }
            />
            {formik.touched.name && formik.errors.name ? (
              <Alert status="error">
                <AlertIcon />
                {formik.errors.name}
              </Alert>
            ) : null}
          </Stack>
          <Stack>
            <Text>Email</Text>
            <Input
              id="email"
              name="email"
              type="text"
              onChange={formik.handleChange}
              onBlur={formik.handleBlur}
              value={formik.values.email}
              placeholder="Enter here"
              isInvalid={
                formik.touched.email && formik.errors.email ? true : false
              }
            />
            {formik.touched.email && formik.errors.email ? (
              <Alert status="error">
                <AlertIcon />
                {formik.errors.email}
              </Alert>
            ) : null}
          </Stack>
          <Stack>
            <Text>Password</Text>
            <Input
              id="password"
              name="password"
              type="password"
              onChange={formik.handleChange}
              onBlur={formik.handleBlur}
              value={formik.values.password}
              placeholder="Enter here"
              isInvalid={
                formik.touched.password && formik.errors.password ? true : false
              }
            />
            {formik.touched.password && formik.errors.password ? (
              <Alert status="error">
                <AlertIcon />
                {formik.errors.password}
              </Alert>
            ) : null}
          </Stack>
          {/* Register */}
          <div className="flex items-center  mt-4">
            <button
              style={{ backgroundColor: "#3747D4" }}
              className="px-4 py-2 text-white rounded hover:bg-black focus:outline-none"
              type="submit"
            >
              Register
            </button>
          </div>
        </form>
      </div>
    </div>
  );
}
Example #24
Source File: Form.js    From web-client with Apache License 2.0 4 votes vote down vote up
OrganisationForm = () => {
    const [organisation, setOrganisation] = useState(Organisation);

    const [rootOrganisation, refetchOrganisation] = useFetch('/organisations/root');
    const [loading, setLoading] = useState(false);
    const parentType = 'organisation';
    const parentId = organisation.id;
    const [logo, setLogo] = useState(null);
    const [smallLogo, setSmallLogo] = useState(null);

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

        setLoading(true);
        await secureApiFetch(`/organisations/root`, { method: 'PUT', body: JSON.stringify(organisation) });
        actionCompletedToast('The changes to the organisation has been saved.');
        setLoading(false);
    }

    const handleFormChange = ev => {
        const target = ev.target;

        const name = target.name;
        const value = target.value;

        setOrganisation({ ...organisation, [name]: value });
    };

    useEffect(() => {
        if (rootOrganisation) {
            setOrganisation(rootOrganisation);
            if (rootOrganisation.small_logo_attachment_id !== null) {
                downloadAndDisplayLogo(rootOrganisation.small_logo_attachment_id, 'small_logo');
            } else {
                setSmallLogo(null);
            }

            if (rootOrganisation.logo_attachment_id !== null) {
                downloadAndDisplayLogo(rootOrganisation.logo_attachment_id, 'logo');
            } else {
                setLogo(null);
            }
        }
    }, [rootOrganisation]);

    const downloadAndDisplayLogo = (logoId, type) => {
        secureApiFetch(`/attachments/${logoId}`, { method: 'GET' })
            .then(resp => {
                if (resp.status === 404) {
                    return Promise.reject("Logo not found");
                }
                const contentDispositionHeader = resp.headers.get('Content-Disposition');
                const filenameRe = new RegExp(/filename="(.*)";/)
                const filename = filenameRe.exec(contentDispositionHeader)[1]
                return Promise.all([resp.blob(), filename]);
            })
            .then((values) => {
                const blob = values[0];
                const url = URL.createObjectURL(blob);
                if (type === 'small_logo') {
                    setSmallLogo(url);
                } else {
                    setLogo(url);
                }
            })
    }

    const onUploadFinished = (type, id) => {
        if (id) {
            setOrganisation({ ...organisation, [type]: id });
            organisation[type] = id;
            setLoading(true);
            secureApiFetch(`/organisations/root`, { method: 'PUT', body: JSON.stringify(organisation) })
                .then(ev => {
                    // has to be done after PUT is completed. Therefore it cannot be merged with the case when ID is null
                    refetchOrganisation();
                })
            setLoading(false);
        } else {
            refetchOrganisation();
        }
    };

    const removeAttachment = (ev, id) => {
        secureApiFetch(`/attachments/${id}`, { method: 'DELETE' })
            .then(resp => {
                if (resp.status === 204) {
                    actionCompletedToast("Logo removed");
                    refetchOrganisation();
                }
            })
    }

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

    return <div>
        <div className='heading'>
            <Breadcrumb />
        </div>
        <form onSubmit={onFormSubmit}>
            <Title title="Settings" type="Organisation" icon={<IconPreferences />} />
            <label>Name
                <Input type="text" name="name" value={organisation.name} onChange={handleFormChange} required
                    autoFocus /></label>
            <label>URL
                <Input type="text" name="url" value={organisation.url} onChange={handleFormChange} /></label>
            <label>Contact name
                <Input type="text" name="contact_name" value={organisation.contact_name || ""} onChange={handleFormChange}
                /></label>
            <label>Contact email
                <Input type="email" name="contact_email" value={organisation.contact_email || ""}
                    onChange={handleFormChange} /></label>
            <label>Contact phone
                <Input type="tel" name="contact_phone" value={organisation.contact_phone || ""}
                    onChange={handleFormChange} /></label>

            <PrimaryButton type="submit"
                disabled={loading}>Save</PrimaryButton>

            <label>Main logo
                <div>
                    {logo && <div><img src={logo} alt="The main organisation logo" /><br /><Button onClick={ev => removeAttachment(ev, organisation.logo_attachment_id)}>Remove</Button></div>}
                    {logo === null && <RestrictedComponent roles={['administrator', 'superuser', 'user']} message="(access restricted)">
                        <AttachmentsImageDropzone parentType={parentType} parentId={parentId} onUploadFinished={onUploadFinished} uploadFinishedParameter="logo_attachment_id" attachmentId={organisation.logo_attachment_id} maxFileCount={1} />
                    </RestrictedComponent>}
                </div>
            </label>

            <label>Small logo
                <div>
                    {smallLogo && <div><img src={smallLogo} alt="The smaller version of the logo" /><br /><Button onClick={ev => removeAttachment(ev, organisation.small_logo_attachment_id)}>Remove</Button></div>}
                    {smallLogo === null && <RestrictedComponent roles={['administrator', 'superuser', 'user']} message="(access restricted)">
                        <AttachmentsImageDropzone parentType={parentType} parentId={parentId} onUploadFinished={onUploadFinished} uploadFinishedParameter="small_logo_attachment_id" attachmentId={organisation.small_logo_attachment_id} maxFileCount={1} />
                    </RestrictedComponent>}
                </div>
            </label>

        </form>
    </div>
}
Example #25
Source File: Todo.js    From benjamincarlson.io with MIT License 4 votes vote down vote up
Todo = () => {
    const toast = useToast()
    const { colorMode } = useColorMode()
    const { isOpen, onOpen, onClose } = useDisclosure()

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

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

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

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

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

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

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

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

                    <ModalFooter>
                        <Button colorScheme="blue" mr={3} onClick={onClose}>
                            Close
                        </Button>
                        <Link
                            href="https://github.com/bjcarlson42/benjamincarlson.io/blob/master/components/Todo.js"
                            _hover={{ textDecor: 'none' }}
                            isExternal
                        >
                            <Button variant="ghost">View Code</Button>
                        </Link>
                    </ModalFooter>
                </ModalContent>
            </Modal>
        </>
    )
}
Example #26
Source File: ProductAddEdit.js    From react-sample-projects with MIT License 4 votes vote down vote up
ProductAddEdit = () => {
  const categories = useSelector(state => state.product.categories);
  const dispatch = useDispatch();
  const navigate = useNavigate();

  const initialValues = {
    title: '',
    price: '',
    category: '',
    description: '',
    image: '',
  };

  const validationSchema = yup.object({
    title: yup.string().required(),
    price: yup.number().required(),
    category: yup.string().required(),
    description: yup.string().required(),
    image: yup.string().url().required(),
  });

  const onFormSubmit = (values, actions) => {
    actions.setSubmitting(false);
    dispatch(addNewProduct(values));
    navigate('/');
  };

  useEffect(() => {
    dispatch(fetchCategories());
    return () => {};
  }, [dispatch]);

  return (
    <Box boxShadow="base" m={'auto'} width="clamp(300px, 60%, 100%)">
      <Formik
        initialValues={initialValues}
        onSubmit={onFormSubmit}
        validationSchema={validationSchema}
      >
        {props => (
          <Form noValidate>
            <VStack p={3} m="3">
              <Box fontWeight="semibold" mt="1" as="h2" textAlign="left">
                Add Product
              </Box>

              <Field name="title">
                {({ field, form }) => (
                  <FormControl
                    isRequired
                    isInvalid={form.errors.title && form.touched.title}
                  >
                    <FormLabel htmlFor="title">Enter Title</FormLabel>
                    <Input
                      {...field}
                      type="text"
                      id="title"
                      placeholder="Enter Title"
                    />
                    <ErrorMessage
                      name="title"
                      component={FormErrorMessage}
                    ></ErrorMessage>
                  </FormControl>
                )}
              </Field>

              <Field name="price">
                {({ field, form }) => (
                  <FormControl
                    isRequired
                    isInvalid={form.errors.price && form.touched.price}
                  >
                    <FormLabel>Enter price</FormLabel>
                    <Input type="number" placeholder="Enter price" {...field} />
                    <ErrorMessage
                      name="price"
                      component={FormErrorMessage}
                    ></ErrorMessage>
                  </FormControl>
                )}
              </Field>
              <Field name="category">
                {({ field, form }) => (
                  <FormControl
                    name="category"
                    isRequired
                    isInvalid={form.errors.category && form.touched.category}
                  >
                    <FormLabel>Enter category</FormLabel>
                    <Select placeholder="Select category" {...field}>
                      {categories.map((category, index) => (
                        <option key={index}>{category}</option>
                      ))}
                    </Select>
                    <ErrorMessage
                      name="category"
                      component={FormErrorMessage}
                    ></ErrorMessage>
                  </FormControl>
                )}
              </Field>
              <Field name="description">
                {({ field, form }) => (
                  <FormControl
                    name="description"
                    isRequired
                    isInvalid={
                      form.errors.description && form.touched.description
                    }
                  >
                    <FormLabel>Enter description</FormLabel>
                    <Textarea
                      {...field}
                      id="description"
                      placeholder="Enter description"
                    ></Textarea>
                    <ErrorMessage
                      name="description"
                      component={FormErrorMessage}
                    ></ErrorMessage>
                  </FormControl>
                )}
              </Field>
              <Field name="image">
                {({ field, form }) => (
                  <FormControl
                    name="image"
                    isRequired
                    isInvalid={form.errors.image && form.touched.image}
                  >
                    <FormLabel>Enter image</FormLabel>
                    <Input
                      type="url"
                      placeholder="Enter image url"
                      {...field}
                    />

                    <ErrorMessage
                      name="image"
                      component={FormErrorMessage}
                    ></ErrorMessage>
                  </FormControl>
                )}
              </Field>
              <Button
                mt={4}
                colorScheme="teal"
                type="submit"
                isLoading={props.isSubmitting}
              >
                Add Product
              </Button>
            </VStack>
          </Form>
        )}
      </Formik>
    </Box>
  );
}
Example #27
Source File: ModalDialog.js    From web-client with Apache License 2.0 4 votes vote down vote up
ReportVersionModalDialog = ({ projectId, isOpen, onSubmit, onCancel }) => {
    const defaultFormValues = { reportTemplateId: 0, name: "", description: "" };
    const [formValues, setFormValues] = useState(defaultFormValues);
    const [templates] = useFetch('/reports/templates');

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

        setFormValues({ ...formValues, [ev.target.name]: ev.target.value });
    };

    const beforeCancelCallback = ev => {
        setFormValues(defaultFormValues);
        onCancel(ev);
    }

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

        const params = {
            projectId: projectId,
            reportTemplateId: formValues.reportTemplateId,
            name: formValues.name,
            description: formValues.description
        };

        secureApiFetch(`/reports`, { method: 'POST', body: JSON.stringify(params) })
            .then(() => {
                onSubmit();
                actionCompletedToast(`The report version "${formValues.name}" has been added.`);
            })
            .catch(err => {
                console.error(err);
            })
            .finally(() => {
                setFormValues(defaultFormValues)
            })
    }

    useEffect(() => {
        if (templates !== null && templates.length > 0) {
            setFormValues((prev) => ({ ...prev, reportTemplateId: templates[0].id }))
        }
    }, [templates]);

    return <Modal size="xl" isOpen={isOpen} onClose={beforeCancelCallback}>
        <ModalOverlay />
        <ModalContent>
            <ModalHeader><HStack><TargetIcon style={{ width: '24px' }} /> <h4>New report version details</h4></HStack></ModalHeader>
            <ModalCloseButton />
            <ModalBody>
                <form id="reportVersionReportForm" onSubmit={onFormSubmit} className="crud" style={{ marginTop: '20px' }}>
                    <FormControl isRequired>
                        <FormLabel>Template</FormLabel>
                        {templates && <Select name="reportTemplateId" value={formValues.reportTemplateId} onChange={onFormValueChange}>
                            {templates.map(template => <option key={template.id} value={template.id}>{template.version_name}</option>)}
                        </Select>}
                    </FormControl>

                    <FormControl isRequired>
                        <FormLabel>Name</FormLabel>
                        <Input type="text" name="name" value={formValues.name} onChange={onFormValueChange}
                            placeholder="eg 1.0, 202103" autoFocus />
                    </FormControl>

                    <FormControl isRequired>
                        <FormLabel>Description</FormLabel>
                        <Input type="text" name="description" value={formValues.description}
                            onChange={onFormValueChange}
                            placeholder="eg Initial version, Draft"
                        />
                    </FormControl>
                </form>
            </ModalBody>

            <ModalFooter>
                <Button onClick={beforeCancelCallback} mr={3}>Cancel</Button>
                <Button form="reportVersionReportForm" type="submit" colorScheme="blue">Save</Button>
            </ModalFooter>
        </ModalContent>
    </Modal>
}
Example #28
Source File: components.js    From idena-web with MIT License 4 votes vote down vote up
export function CommunityTranslations({
  keywords,
  isOpen,
  isPending,
  onVote,
  onSuggest,
  onToggle,
}) {
  const {t} = useTranslation()

  const {privateKey} = useAuthState()

  const [wordIdx, setWordIdx] = React.useState(0)

  const [
    descriptionCharactersCount,
    setDescriptionCharactersCount,
  ] = React.useState(150)

  const translations = keywords.translations[wordIdx]

  const lastTranslationId =
    translations && translations.length
      ? translations[translations.length - 1].id
      : wordIdx

  return (
    <Stack spacing={isOpen ? 8 : 0}>
      <IconButton
        icon={<CommunityIcon boxSize={5} />}
        color="brandGray.500"
        px={0}
        _hover={{background: 'transparent'}}
        onClick={onToggle}
      >
        {t('Community translation')}
        <ChevronDownIcon boxSize={5} color="muted" ml={2} />
      </IconButton>
      <Collapse isOpen={isOpen}>
        <Stack spacing={8}>
          <RadioGroup isInline value={wordIdx} onChange={setWordIdx}>
            {keywords.words.map(({id, name}, i) => (
              <FlipKeywordRadio key={id} value={i}>
                {name && capitalize(name)}
              </FlipKeywordRadio>
            ))}
          </RadioGroup>
          {translations.map(({id, name, desc, score}) => (
            <Flex key={id} justify="space-between">
              <FlipKeyword>
                <FlipKeywordName>{name}</FlipKeywordName>
                <FlipKeywordDescription>{desc}</FlipKeywordDescription>
              </FlipKeyword>
              <Stack isInline spacing={2} align="center">
                <VoteButton
                  icon={<UpvoteIcon />}
                  onClick={() => onVote({id, up: true, pk: privateKey})}
                />
                <Flex
                  align="center"
                  justify="center"
                  bg={score < 0 ? 'red.010' : 'green.010'}
                  color={score < 0 ? 'red.500' : 'green.500'}
                  fontWeight={500}
                  rounded="md"
                  minW={12}
                  minH={8}
                  style={{fontVariantNumeric: 'tabular-nums'}}
                >
                  {score}
                </Flex>
                <VoteButton
                  icon={<UpvoteIcon />}
                  color="muted"
                  transform="rotate(180deg)"
                  onClick={() => onVote({id, up: false, pk: privateKey})}
                />
              </Stack>
            </Flex>
          ))}

          {translations.length && <Divider borderColor="gray.100" />}

          <Box>
            <Text fontWeight={500} mb={3}>
              {t('Suggest translation')}
            </Text>
            <form
              key={lastTranslationId}
              onSubmit={e => {
                e.preventDefault()
                const {
                  nameInput: {value: name},
                  descInput: {value: desc},
                } = e.target.elements
                onSuggest({wordIdx, name, desc: desc.trim(), pk: privateKey})
              }}
            >
              <FormControl>
                <Input
                  id="nameInput"
                  placeholder={
                    keywords.words[wordIdx].name
                      ? capitalize(keywords.words[wordIdx].name)
                      : 'Name'
                  }
                  px={3}
                  pt={1.5}
                  pb={2}
                  borderColor="gray.100"
                  mb={2}
                  _placeholder={{
                    color: 'muted',
                  }}
                />
              </FormControl>
              <FormControl position="relative">
                <Textarea
                  id="descInput"
                  placeholder={
                    keywords.words[wordIdx].desc
                      ? capitalize(keywords.words[wordIdx].desc)
                      : 'Description'
                  }
                  mb={6}
                  onChange={e =>
                    setDescriptionCharactersCount(150 - e.target.value.length)
                  }
                />
                <Box
                  color={descriptionCharactersCount < 0 ? 'red.500' : 'muted'}
                  fontSize="sm"
                  position="absolute"
                  right={2}
                  bottom={2}
                  zIndex="docked"
                >
                  {descriptionCharactersCount}
                </Box>
              </FormControl>
              <PrimaryButton
                type="submit"
                display="flex"
                ml="auto"
                isLoading={isPending}
              >
                {t('Send')}
              </PrimaryButton>
            </form>
          </Box>
        </Stack>
      </Collapse>
    </Stack>
  )
}
Example #29
Source File: playlists.js    From grandcast.fm with Apache License 2.0 4 votes vote down vote up
export default function Playlists() {
  const { isSignedIn } = useAuth()
  const [selectedPlaylist, setSelectedPlaylist] = useState('')
  const [newPlaylist, setNewPlaylist] = useState('')
  const { data } = useQuery(GET_PLAYLISTS)
  const [createPlaylist] = useMutation(CREATE_PLAYLIST)

  const filteredPlaylist = data?.playlists?.filter((p) => {
    return p.name === selectedPlaylist
  })[0]

  return (
    <Container>
      {!isSignedIn() && <SignIn />}
      {isSignedIn() && (
        <div>
          <FormControl id="playlists">
            <Flex>
              <Select
                placeholder="Select playlist"
                onChange={(e) => setSelectedPlaylist(e.target.value)}
              >
                {data?.playlists?.map((p) => {
                  return (
                    <option key={p.name} value={p.value}>
                      {p.name}
                    </option>
                  )
                })}
              </Select>
              <Popover>
                <PopoverTrigger>
                  <Button ml={4}>
                    <AddIcon />
                  </Button>
                </PopoverTrigger>
                <PopoverContent>
                  <PopoverArrow />
                  <PopoverCloseButton />
                  <PopoverHeader>Create new playlist</PopoverHeader>
                  <PopoverBody>
                    <FormControl id="newplaylist">
                      <Input
                        type="text"
                        onChange={(e) => setNewPlaylist(e.target.value)}
                      />
                      <Button
                        mt={4}
                        onClick={() =>
                          createPlaylist({
                            variables: { playlistName: newPlaylist },
                            update: (proxy) => {
                              const data = proxy.readQuery({
                                query: GET_PLAYLISTS,
                              })

                              proxy.writeQuery({
                                query: GET_PLAYLISTS,
                                data: {
                                  playlists: [
                                    ...data.playlists,
                                    {
                                      __typename: 'Playlist',
                                      name: newPlaylist,
                                    },
                                  ],
                                },
                              })
                            },
                          })
                        }
                      >
                        Create
                      </Button>
                    </FormControl>
                  </PopoverBody>
                </PopoverContent>
              </Popover>
            </Flex>
          </FormControl>
          <VStack mt={4} spacing={4}>
            {filteredPlaylist?.episodes?.map((e) => {
              return (
                <Episode key={e.id} episode={e} playlists={data.playlists} />
              )
            })}
          </VStack>
        </div>
      )}
    </Container>
  )
}