@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 |
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 |
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 |
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&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 |
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 |
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 |
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 |
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 |
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 |
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 |
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 |
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 |
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 |
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 |
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 |
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 |
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 |
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 |
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}>
{" "}
>{" "}
</Button>
</Flex>
</Box>
<Box></Box>
</DrawerBody>
</DrawerContent>
</Drawer>
<Toaster />
</Box>
);
}
Example #19
Source File: MakeClaim.js From DAOInsure with MIT License | 4 votes |
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 |
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 |
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 |
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 |
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 |
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 |
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 |
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 |
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 |
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 |
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>
)
}