@chakra-ui/react#Alert JavaScript Examples
The following examples show how to use
@chakra-ui/react#Alert.
You can vote up the ones you like or vote down the ones you don't like,
and go to the original project or source file by following the links above each example. You may check out the related API usage on the sidebar.
Example #1
Source File: components.js From idena-web with MIT License | 6 votes |
function ErrorAlert(props) {
return (
<Alert
status="error"
bg="red.500"
borderWidth="1px"
borderColor="red.050"
fontWeight={500}
color="white"
rounded="md"
px={6}
py={4}
w={['auto', '480px']}
mt={2}
{...props}
/>
)
}
Example #2
Source File: Messages.jsx From realtime-chat-supabase-react with Apache License 2.0 | 6 votes |
export default function Messages() {
const { username, loadingInitial, error, getMessagesAndSubscribe, messages } =
useAppContext();
const reversed = [...messages].reverse();
if (loadingInitial)
return (
<Box textAlign="center">
<Spinner />
</Box>
);
if (error)
return (
<Alert status="error" mt="20px">
{error}
<Button
ml="5px"
onClick={getMessagesAndSubscribe}
colorScheme="red"
variant="link"
>
try to reconnect
</Button>
</Alert>
);
if (!messages.length)
return (
<Box as="h3" textAlign="center">
No messages ?
</Box>
);
return reversed.map((message) => {
const isYou = message.username === username;
return <Message key={message.id} message={message} isYou={isYou} />;
});
}
Example #3
Source File: PageNotFound.js From web-client with Apache License 2.0 | 6 votes |
PageNotFound = () => {
return <Alert
status='error'
variant='subtle'
flexDirection='column'
alignItems='center'
justifyContent='center'
textAlign='center'
>
<AlertIcon boxSize='40px' mr={0} />
<AlertTitle mt={4} mb={1} fontSize='lg'>
Page not found
</AlertTitle>
<AlertDescription>
There is nothing at this address. Please navigate to another place.
</AlertDescription>
</Alert>
}
Example #4
Source File: components.js From idena-web with MIT License | 6 votes |
export function WarningAlert({children, ...props}) {
return (
<Alert
status="warning"
bg="warning.010"
borderWidth="1px"
borderColor="warning.050"
fontSize="md"
fontWeight={500}
rounded="md"
px={3}
py={2}
{...props}
>
<InfoIcon color="warning.500" boxSize={5} mr={3} />
{children}
</Alert>
)
}
Example #5
Source File: components.js From idena-web with MIT License | 6 votes |
export function ErrorAlert({children, ...props}) {
return (
<Alert
status="error"
bg="red.010"
borderWidth="1px"
borderColor="red.050"
fontSize="md"
fontWeight={500}
rounded="md"
px={3}
py={2}
{...props}
>
<InfoIcon color="red.500" boxSize="5" mr={3} />
{children}
</Alert>
)
}
Example #6
Source File: components.js From idena-web with MIT License | 6 votes |
export function SuccessAlert({icon, children, ...props}) {
return (
<Alert
status="success"
bg="green.010"
borderWidth="1px"
borderColor="green.050"
fontWeight={500}
rounded="md"
px={3}
py={2}
{...props}
>
{icon || <AlertIcon color="green.500" boxSize={5} mr={3} />}
{children}
</Alert>
)
}
Example #7
Source File: components.js From idena-web with MIT License | 6 votes |
export function CommunityTranslationUnavailable() {
const {t} = useTranslation()
return (
<Box mt={4}>
<Alert
status="error"
bg="red.010"
borderWidth="1px"
borderColor="red.050"
fontWeight={500}
rounded="md"
px={3}
py={2}
>
<AlertIcon name="info" color="red.500" size={5} mr={3} />
{t('Community translation is not available')}
</Alert>
</Box>
)
}
Example #8
Source File: MDXComponents.js From benjamincarlson.io with MIT License | 6 votes |
Quote = (props) => {
const { colorMode } = useColorMode()
const bgColor = {
light: 'blue.50',
dark: 'blue.900'
}
return (
<Alert
mt={4}
w="98%"
bg={bgColor[colorMode]}
variant="left-accent"
status="info"
css={{
'> *:first-of-type': {
marginTop: 0,
marginLeft: 8
}
}}
{...props}
/>
)
}
Example #9
Source File: Results.js From web-client with Apache License 2.0 | 5 votes |
SearchResults = React.memo(() => {
const params = useParams();
const query = useQuery();
const keywords = decodeURIComponent(params.keywords);
const entitiesParam = query.has('entities') ? query.get('entities') : 'commands,tasks,vulnerabilities,vulnerability_templates,projects,project_templates';
const entities = useMemo(() => entitiesParam.split(','), [entitiesParam]);
const [emptyResults, setEmptyResults] = useState([]);
return <>
<PageTitle value={`${keywords} search results`} />
<div className='heading'>
<Breadcrumb />
<div>
<LinkButton href="/advanced-search">Advanced search</LinkButton>
</div>
</div>
<Title type='Search results' title={`For ${keywords}`} icon={<IconSearch />} />
{emptyResults.length > 0 &&
<Alert status="warning">
<AlertIcon />
No results were found for: {[...new Set([...emptyResults])].join(', ')}
</Alert>
}
{entities.includes('commands') &&
<CommandsSearchResults keywords={keywords} emptyResultsSetter={setEmptyResults} />}
{entities.includes('tasks') &&
<TasksSearchResults keywords={keywords} emptyResultsSetter={setEmptyResults} />}
{entities.includes('vulnerabilities') &&
<VulnerabilitiesSearchResults keywords={keywords} emptyResultsSetter={setEmptyResults} />}
{entities.includes('vulnerability_templates') &&
<VulnerabilityTemplatesSearchResults keywords={keywords} emptyResultsSetter={setEmptyResults} />}
{entities.includes('projects') &&
<ProjectsSearchResults keywords={keywords} emptyResultsSetter={setEmptyResults} />}
{entities.includes('project_templates') &&
<ProjectTemplatesSearchResults keywords={keywords} emptyResultsSetter={setEmptyResults} />}
</>
})
Example #10
Source File: NotificationsBadge.js From web-client with Apache License 2.0 | 5 votes |
NotificationsBadge = () => {
const [notifications, fetchNotifications] = useFetch('/notifications?status=unread');
const onMessageHandler = () => {
fetchNotifications();
}
useWebsocketMessage(onMessageHandler);
const markAsRead = notification => {
secureApiFetch(`/notifications/${notification.id}`, {
method: 'PUT',
body: JSON.stringify({ status: 'read' })
}).then(() => {
fetchNotifications();
})
}
return <Popover placement="bottom-end" closeOnBlur={true}>
<PopoverTrigger>
<Button pr={null !== notifications && notifications.length > 0 ? 1 : 2} variant="ghost" aria-label="Notifications" >
<BellIcon fontSize="xl" color="gray.500" />
{null !== notifications && notifications.length > 0 && (
<Tag colorScheme='red' >{notifications.length}</Tag>
)}
</Button>
</PopoverTrigger>
<PopoverContent>
<PopoverArrow />
<PopoverHeader px="3" pb="3" color="gray.500">
<Link to="/notifications">Notifications</Link>
</PopoverHeader>
<PopoverBody>
{null !== notifications && notifications.length > 0 ? (
<Stack>
{notifications.map(notification =>
<Alert key={notification.id} status='info' variant="top-accent">
<Box flex='1'>
<AlertTitle>{notification.time} <strong><Link to="/vulnerabilities">{notification.title}</Link></strong></AlertTitle>
<AlertDescription display='block'>{notification.content}</AlertDescription>
</Box>
<CloseButton position='absolute' right='8px' top='8px' onClick={() => markAsRead(notification)} />
</Alert>
)}
</Stack>
) : <span>Nothing to see here.</span>}
</PopoverBody>
</PopoverContent>
</Popover>
}
Example #11
Source File: components.js From idena-web with MIT License | 5 votes |
export function Toast({
title,
description,
icon = 'info',
status = 'info',
actionContent,
actionColor = status === 'error' ? 'red.500' : 'brandBlue.500',
color,
onAction,
duration,
...props
}) {
return (
<Alert
status={status}
bg="white"
boxShadow="0 3px 12px 0 rgba(83, 86, 92, 0.1), 0 2px 3px 0 rgba(83, 86, 92, 0.2)"
color={color || 'brandGray.500'}
fontSize="md"
pl={4}
pr={actionContent ? 2 : 5}
pt="10px"
pb={3}
mb={5}
minH="44px"
rounded="lg"
{...props}
>
<AlertIcon
name={icon}
size={5}
color={color || (status === 'error' ? 'red.500' : 'blue.500')}
/>
<Flex direction="column" align="flex-start" maxW={['90vw', 'sm']}>
<AlertTitle fontWeight={500} lineHeight="base">
{title}
</AlertTitle>
<AlertDescription
color={color || 'muted'}
lineHeight="base"
textAlign="left"
maxW={['77vw', 'none']}
w="full"
isTruncated
>
{description}
</AlertDescription>
</Flex>
{actionContent && (
<Button
variant="ghost"
color={actionColor}
fontWeight={500}
lineHeight="base"
px={3}
py="3/2"
_hover={{bg: 'unset'}}
_active={{bg: 'unset'}}
_focus={{boxShadow: 'none'}}
onClick={onAction}
>
{actionContent}
</Button>
)}
<Box
bg="gray.100"
height="3px"
roundedBottom={2}
pos="absolute"
bottom={0}
left={0}
right={0}
animation={`${escape} ${duration}ms linear forwards`}
/>
</Alert>
)
}
Example #12
Source File: containers.js From idena-web with MIT License | 5 votes |
export function DnaSendSucceededDialog({hash, url, onCompleteSend, ...props}) {
const {t} = useTranslation()
return (
<Dialog closeOnOverlayClick={false} closeOnEsc={false} {...props}>
<DialogBody color="brandGray.500">
<Stack spacing={5}>
<Alert
status="success"
bg="green.010"
borderRadius="lg"
flexDirection="column"
justifyContent="center"
height={132}
>
<Stack spacing={2} align="center">
<AlertIcon size={8} mr={0} />
<AlertTitle fontSize="lg" fontWeight={500}>
{t('Successfully sent')}
</AlertTitle>
</Stack>
</Alert>
<Stack spacing={1}>
<Stack spacing={1} py={2}>
<Box color="muted">{t('Tx hash')}</Box>
<Box wordBreak="break-all" fontWeight={500}>
{hash}
</Box>
</Stack>
<ExternalLink href={`https://scan.idena.io/transaction/${hash}`}>
{t('Open in blockchain explorer')}
</ExternalLink>
</Stack>
</Stack>
</DialogBody>
<DialogFooter>
{url ? (
<PrimaryButton
onClick={() => {
openExternalUrl(url)
onCompleteSend()
}}
>
{t('Continue')}
</PrimaryButton>
) : (
<PrimaryButton onClick={onCompleteSend}>{t('Close')}</PrimaryButton>
)}
</DialogFooter>
</Dialog>
)
}
Example #13
Source File: list.js From idena-web with MIT License | 4 votes |
export default function FlipListPage() {
const {t} = useTranslation()
const toast = useToast()
const epochState = useEpoch()
const {privateKey} = useAuthState()
const {
isOpen: isOpenDeleteForm,
onOpen: openDeleteForm,
onClose: onCloseDeleteForm,
} = useDisclosure()
const [
{
flips: knownFlips,
requiredFlips: requiredFlipsNumber,
availableFlips: availableFlipsNumber,
state: status,
},
] = useIdentity()
const [selectedFlip, setSelectedFlip] = React.useState()
const canSubmitFlips = [
IdentityStatus.Verified,
IdentityStatus.Human,
IdentityStatus.Newbie,
].includes(status)
const [current, send] = useMachine(flipsMachine, {
context: {
knownFlips: knownFlips || [],
filter: loadPersistentState('flipFilter') || FlipFilterType.Active,
},
actions: {
onError: (_, {error}) =>
toast({
title: error,
status: 'error',
duration: 5000,
isClosable: true,
// eslint-disable-next-line react/display-name
render: () => (
<Box fontSize="md">
<Notification title={error} type={NotificationType.Error} />
</Box>
),
}),
},
logger: msg => console.log(redact(msg)),
})
useEffect(() => {
if (epochState && privateKey && status) {
send('INITIALIZE', {epoch: epochState.epoch, privateKey, canSubmitFlips})
}
}, [canSubmitFlips, epochState, privateKey, send, status])
const {flips, missingFlips, filter} = current.context
const filterFlips = () => {
switch (filter) {
case FlipFilterType.Active:
return flips.filter(({type}) =>
[
FlipType.Publishing,
FlipType.Published,
FlipType.Deleting,
FlipType.Invalid,
].includes(type)
)
case FlipType.Draft:
return flips.filter(({type}) => type === FlipType.Draft)
case FlipType.Archived:
return flips.filter(({type}) =>
[FlipType.Archived, FlipType.Deleted].includes(type)
)
default:
return []
}
}
const madeFlipsNumber = (knownFlips || []).length
const remainingRequiredFlips = requiredFlipsNumber - madeFlipsNumber
const remainingOptionalFlips =
availableFlipsNumber - Math.max(requiredFlipsNumber, madeFlipsNumber)
const [currentOnboarding, {dismissCurrentTask}] = useOnboarding()
const eitherOnboardingState = (...states) =>
eitherState(currentOnboarding, ...states)
return (
<Layout>
<Page pt={[4, 6]}>
<MobileApiStatus display={['initial', 'none']} left={4} />
<PageTitleNew>{t('My Flips')}</PageTitleNew>
<Flex justify="space-between" align="center" alignSelf="stretch" mb={8}>
<Stack spacing={2} isInline>
<Button
variant="tab"
onClick={() => send('FILTER', {filter: FlipFilterType.Active})}
isActive={filter === FlipFilterType.Active}
>
{t('Active')}
</Button>
<Button
variant="tab"
onClick={() => send('FILTER', {filter: FlipFilterType.Draft})}
isActive={filter === FlipFilterType.Draft}
>
{t('Drafts')}
</Button>
<Button
variant="tab"
onClick={() => send('FILTER', {filter: FlipFilterType.Archived})}
isActive={filter === FlipFilterType.Archived}
>
{t('Archived')}
</Button>
</Stack>
<Box alignSelf="end">
<OnboardingPopover
isOpen={eitherOnboardingState(
onboardingShowingStep(OnboardingStep.CreateFlips)
)}
>
<PopoverTrigger>
<Box onClick={dismissCurrentTask}>
<IconLink
icon={<PlusSolidIcon boxSize={5} mt={1} />}
href="/flips/new"
bg="white"
position={
eitherOnboardingState(
onboardingShowingStep(OnboardingStep.CreateFlips)
)
? 'relative'
: 'initial'
}
zIndex={2}
>
{t('New flip')}
</IconLink>
</Box>
</PopoverTrigger>
<OnboardingPopoverContent
title={t('Create required flips')}
onDismiss={dismissCurrentTask}
>
<Stack>
<Text>
{t(`You need to create at least 3 flips per epoch to participate
in the next validation ceremony. Follow step-by-step
instructions.`)}
</Text>
<OnboardingPopoverContentIconRow
icon={<RewardIcon boxSize={5} />}
>
{t(
`You'll get rewarded for every successfully qualified flip.`
)}
</OnboardingPopoverContentIconRow>
<OnboardingPopoverContentIconRow
icon={<PenaltyIcon boxSize={5} />}
>
{t(`Read carefully "What is a bad flip" rules to avoid
penalty.`)}
</OnboardingPopoverContentIconRow>
</Stack>
</OnboardingPopoverContent>
</OnboardingPopover>
</Box>
</Flex>
{current.matches('ready.dirty.active') &&
canSubmitFlips &&
(remainingRequiredFlips > 0 || remainingOptionalFlips > 0) && (
<Box alignSelf="stretch" mb={8}>
<Alert
status="success"
bg="green.010"
borderWidth="1px"
borderColor="green.050"
fontWeight={500}
rounded="md"
px={3}
py={2}
>
<AlertIcon name="info" color="green.500" size={5} mr={3} />
{remainingRequiredFlips > 0
? t(
`Please submit {{remainingRequiredFlips}} required flips.`,
{remainingRequiredFlips}
)
: null}{' '}
{remainingOptionalFlips > 0
? t(
`You can also submit {{remainingOptionalFlips}} optional flips if you want.`,
{
remainingOptionalFlips,
}
)
: null}
</Alert>
</Box>
)}
{status && !canSubmitFlips && (
<Box alignSelf="stretch" mb={8}>
<Alert
status="error"
bg="red.010"
borderWidth="1px"
borderColor="red.050"
fontWeight={500}
rounded="md"
px={3}
py={2}
>
<AlertIcon
name="info"
color="red.500"
size={5}
mr={3}
></AlertIcon>
{t('You can not submit flips. Please get validated first. ')}
</Alert>
</Box>
)}
{current.matches('ready.pristine') && (
<Flex
flex={1}
alignItems="center"
justifyContent="center"
alignSelf="stretch"
>
<Image src="/static/flips-cant-icn.svg" />
</Flex>
)}
{current.matches('ready.dirty') && (
<FlipCardList>
{filterFlips().map(flip => (
<FlipCard
key={flip.id}
flipService={flip.ref}
onDelete={() => {
if (
flip.type === FlipType.Published &&
(knownFlips || []).includes(flip.hash)
) {
setSelectedFlip(flip)
openDeleteForm()
} else flip.ref.send('ARCHIVE')
}}
/>
))}
{current.matches('ready.dirty.active') && (
<>
{missingFlips.map(({keywords}, idx) => (
<Box key={idx}>
<EmptyFlipBox>
<Image src="/static/flips-cant-icn.svg" />
</EmptyFlipBox>
<Box mt={4}>
<FlipCardTitle>
{keywords
? formatKeywords(keywords.words)
: t('Missing keywords')}
</FlipCardTitle>
<FlipCardSubtitle>
{t('Missing on client')}
</FlipCardSubtitle>
</Box>
</Box>
))}
{Array.from({length: remainingRequiredFlips}, (flip, idx) => (
<RequiredFlipPlaceholder
key={idx}
title={`Flip #${madeFlipsNumber + idx + 1}`}
{...flip}
/>
))}
{Array.from({length: remainingOptionalFlips}, (flip, idx) => (
<OptionalFlipPlaceholder
key={idx}
title={`Flip #${availableFlipsNumber -
(remainingOptionalFlips - idx - 1)}`}
{...flip}
isDisabled={remainingRequiredFlips > 0}
/>
))}
</>
)}
</FlipCardList>
)}
<DeleteFlipDrawer
hash={selectedFlip?.hash}
cover={selectedFlip?.images[selectedFlip.originalOrder[0]]}
isOpen={isOpenDeleteForm}
onClose={onCloseDeleteForm}
onDelete={() => {
selectedFlip.ref.send('DELETE')
onCloseDeleteForm()
}}
/>
</Page>
</Layout>
)
}
Example #14
Source File: manage-admin.jsx From UpStats with MIT License | 4 votes |
Test = (props) => {
const api = create({
baseURL: `/api`,
});
const toast = useToast();
const router = useRouter();
const [users, setUsers] = useState([]);
const [isLoggedIn, setIsLoggedIn] = useState(false);
const [currentEditUser, setCurrentEditUser] = useState({
email: "",
});
const loadUsers = async () => {
try {
const { data } = await http.get("/users");
setUsers(data);
} catch (e) {
toast({
title: "Error",
description: "Error Loading Users",
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(() => {
loadUsers();
}, []);
const handleDelete = async (user) => {
const originalUsers = users;
const newUsers = originalUsers.filter((s) => s._id !== user._id);
setUsers(newUsers);
try {
await http.delete(`/users/${user._id}`);
} catch (ex) {
if (ex.response && ex.response.status === 404)
toast({
title: "Error",
description: "User May be Already Deleted",
status: "error",
duration: 9000,
isClosable: true,
});
setUsers(originalUsers);
}
};
const handleAdd = async (user) => {
try {
const { data } = await api.post("/users", user, {
headers: localStorage.getItem("token"),
});
setUsers([...users, data]);
} catch (ex) {
toast({
title: "Error",
description: "Submit Unsuccessful",
status: "error",
duration: 9000,
isClosable: true,
});
}
};
const handleEdit = async () => {
const originalUsers = users;
let newUsers = [...users];
const idx = newUsers.findIndex((sys) => sys._id === currentEditUser._id);
newUsers[idx] = { ...currentEditUser };
setUsers(newUsers);
try {
await http.put(`/users/${currentEditUser._id}`, {
email: currentEditUser.email,
});
setCurrentEditUser({ email: "" });
} catch (ex) {
toast({
title: "Error",
description: "Error Updating The User",
status: "error",
duration: 9000,
isClosable: true,
});
setUsers(originalUsers);
setCurrentEditUser({ email: "" });
}
};
const formik = useFormik({
initialValues: {
email: "",
},
validationSchema: Yup.object({
email: Yup.string().label("Email").email().required("Required"),
}),
onSubmit: (values) => {
handleAdd(values);
},
});
return (
<FormikProvider value={formik}>
<Layout>
<>
{isLoggedIn ? (
<>
{/* 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">New Admin</h3>
<form onSubmit={formik.handleSubmit} className="p-3">
<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>
{/* 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>
{users.map((user) => (
<div key={user._id} className="status-items-manage">
<div className="items">
<span className="site-title">{user.name}</span>
<div className="i">
<EditIcon
mr="2"
onClick={() => {
setCurrentEditUser(user);
}}
/>
<DeleteIcon
color="red"
m="2"
onClick={() => {
handleDelete(user);
}}
/>
</div>
</div>
</div>
))}
{/* End */}
{currentEditUser.email ? (
<div className="mt-4">
<Stack>
<h3 className="text-2xl font-black text-black">
Edit User
</h3>
<Stack mt={2}>
<Text>Email</Text>
<Input
placeholder="Enter here"
id="email"
name="email"
type="text"
value={currentEditUser.email}
onChange={(e) =>
setCurrentEditUser({
...currentEditUser,
email: 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>
) : (
""
)}
</div>
</>
) : (
""
)}
</>
</Layout>
</FormikProvider>
);
}
Example #15
Source File: Membership.js From web-client with Apache License 2.0 | 4 votes |
ProjectMembership = () => {
const { projectId } = useParams();
const [users] = useFetch(`/users`)
const [members, updateMembers] = useFetch(`/projects/${projectId}/users`)
const [savedProject] = useFetch(`/projects/${projectId}`);
const [availableUsers, setAvailableUsers] = useState([]);
const handleOnClick = ev => {
ev.preventDefault();
const userId = document.getElementById('userId').value;
const userData = { userId: userId };
secureApiFetch(`/projects/${projectId}/users`, {
method: 'POST',
body: JSON.stringify(userData)
}).then(() => {
updateMembers()
})
}
const handleDelete = (member) => {
secureApiFetch(`/projects/${projectId}/users/${member.membership_id}`, {
method: 'DELETE'
}).then(() => {
updateMembers()
})
}
useEffect(() => {
if (members && users && users.length > 0) {
const memberIds = members.reduce((list, user) => [...list, user.id], []);
setAvailableUsers(users.filter(user => !memberIds.includes(user.id)));
}
}, [members, users]);
return <div>
<PageTitle value="Project membership" />
<div className="heading">
<Breadcrumb>
<Link to="/projects">Projects</Link>
{savedProject && <Link to={`/projects/${savedProject.id}`}>{savedProject.name}</Link>}
</Breadcrumb>
</div>
<Title title='Members' />
{availableUsers.length > 0 ?
<form>
<label>
Select user
<Select id="userId">
{availableUsers && availableUsers.map((user, index) =>
<option key={index} value={user.id}>{user.full_name}</option>
)}
</Select>
</label>
<PrimaryButton onClick={handleOnClick} leftIcon={<IconPlus />}>Add as member</PrimaryButton>
</form> :
<Alert status="info">
<AlertIcon />
All users have been added to the project.
</Alert>
}
<Table>
<Thead>
<Tr>
<Th style={{ width: '80px' }}> </Th>
<Th>Name</Th>
<Th>Role</Th>
<Th> </Th>
</Tr>
</Thead>
<Tbody>
{null === members &&
<LoadingTableRow numColumns={4} />}
{null !== members && 0 === members.length &&
<NoResultsTableRow numColumns={4} />}
{members && members.map((member, index) =>
<Tr key={index}>
<Td><UserAvatar email={member.email} /></Td>
<Td><UserLink userId={member.id}>{member.full_name}</UserLink></Td>
<Td><UserRoleBadge role={member.role} /></Td>
<Td textAlign="right">
<DeleteIconButton onClick={() => handleDelete(member)} />
</Td>
</Tr>
)
}
</Tbody>
</Table>
</div>
}
Example #16
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 #17
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 #18
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 #19
Source File: components.js From idena-web with MIT License | 4 votes |
export function ReviewValidationDialog({
flips,
reportedFlipsCount,
availableReportsCount,
isSubmitting,
onSubmit,
onMisingAnswers,
onMisingReports,
onCancel,
isDesktop,
...props
}) {
const {t} = useTranslation()
const answeredFlipsCount = flips.filter(({option}) => option > 0).length
const areFlipsUnanswered = answeredFlipsCount < flips.length
const areReportsMissing = reportedFlipsCount < availableReportsCount
const NoticeFooter = isDesktop ? DialogFooter : DrawerFooter
const size = useBreakpointValue(['mdx', 'md'])
const variantPrimary = useBreakpointValue(['primaryFlat', 'primary'])
const variantSecondary = useBreakpointValue(['secondaryFlat', 'secondary'])
const approvedCount = flips.filter(
flip => flip.relevance === RelevanceType.Relevant
).length
const abstainedCount = flips.filter(
flip =>
(flip.relevance ?? RelevanceType.Abstained) === RelevanceType.Abstained
).length
return (
<Dialog
title={t('Submit the answers')}
onClose={onCancel}
isDesktop={isDesktop}
isCloseable={false}
{...props}
>
<ValidationDialogBody>
<Stack spacing={6}>
<Stack spacing={4}>
<Stack spacing={2}>
<ReviewValidationDialog.Stat
label={t('Answered')}
value={t('{{answeredFlips}} out of {{totalFlips}}', {
answeredFlips: answeredFlipsCount,
totalFlips: flips.length,
})}
/>
<ReviewValidationDialog.Stat
label={t('Approved')}
value={approvedCount}
/>
<ReviewValidationDialog.Stat
label={t('Reported')}
value={reportedFlipsCount}
/>
{availableReportsCount - reportedFlipsCount > 0 ? (
<ReviewValidationDialog.Stat
label={t('Unused reports')}
value={availableReportsCount - reportedFlipsCount}
/>
) : (
<ReviewValidationDialog.Stat
label={t('Abstained')}
value={abstainedCount}
/>
)}
</Stack>
{(areFlipsUnanswered || areReportsMissing) && (
<Stack>
{areFlipsUnanswered && (
<Text color="muted">
<Trans i18nKey="reviewMissingFlips" t={t}>
You need to answer{' '}
<ReviewValidationDialog.LinkButton
onClick={onMisingAnswers}
>
all flips
</ReviewValidationDialog.LinkButton>{' '}
otherwise you may fail the validation.
</Trans>
</Text>
)}
{areReportsMissing && (
<Text color="muted">
<Trans i18nKey="reviewMissingReports" t={t}>
Use{' '}
<ReviewValidationDialog.LinkButton
variant="link"
onClick={onMisingReports}
>
all available reports
</ReviewValidationDialog.LinkButton>{' '}
to get maximum rewards.
</Trans>
</Text>
)}
</Stack>
)}
</Stack>
{areReportsMissing && (
<Alert
status="error"
bg="red.010"
borderWidth="1px"
borderColor="red.050"
fontWeight={500}
rounded="md"
px={3}
py={2}
>
<AlertIcon name="info" color="red.500" size={5} mr={3} />
{t('You may lose rewards. Are you sure?')}
</Alert>
)}
</Stack>
</ValidationDialogBody>
<NoticeFooter {...props}>
<Button
variant={variantSecondary}
size={size}
w={['100%', 'auto']}
onClick={onCancel}
>
{t('Cancel')}
</Button>
<Divider
display={['block', 'none']}
h={10}
orientation="vertical"
color="gray.100"
/>
<Button
variant={variantPrimary}
size={size}
w={['100%', 'auto']}
isLoading={isSubmitting}
loadingText={t('Submitting answers...')}
onClick={onSubmit}
>
{isDesktop ? t('Submit answers') : t('Submit')}
</Button>
</NoticeFooter>
</Dialog>
)
}
Example #20
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 #21
Source File: components.js From idena-web with MIT License | 4 votes |
export function MyIdenaBotAlert({onConnect, onSkip}) {
const {t} = useTranslation()
const [{state}] = useIdentity()
const myIdenaBotDisclosure = useDisclosure()
const [doNotShowAgain, setDoNotShowAgain] = React.useState()
const connectButtonRef = React.useRef()
// eslint-disable-next-line no-shadow
const eitherState = (...states) => states.some(s => s === state)
const size = useBreakpointValue(['sm', 'md'])
const isDesktop = useIsDesktop()
return (
<>
<Alert
variant="solid"
justifyContent="center"
flexShrink={0}
boxShadow="0 3px 12px 0 rgb(255 163 102 /0.1), 0 2px 3px 0 rgb(255 163 102 /0.2)"
color="white"
cursor="pointer"
fontWeight={500}
rounded="md"
mt={2}
mx={2}
w="auto"
onClick={myIdenaBotDisclosure.onOpen}
>
<Flex flexGrow={1} justifyContent="center" position="relative">
<Box mr={[5, 0]}>
<TelegramIcon boxSize={6} mr={1} display={['none', 'initial']} />
{t(`Subscribe to @MyIdenaBot to get personalized notifications based on
your status`)}
</Box>
{isDesktop ? (
<FlatButton
p={2}
position="absolute"
right={0}
top={0}
height="100%"
color="white"
onClick={e => {
e.stopPropagation()
onSkip()
}}
_hover={{color: 'white'}}
>
{t('Close')}
</FlatButton>
) : (
<CloseButton
position="absolute"
right={-3}
top={-2}
onClick={e => {
e.stopPropagation()
onSkip()
}}
/>
)}
</Flex>
</Alert>
<Dialog
title="Subscribe to @MyIdenaBot"
size={size}
initialFocusRef={connectButtonRef}
{...myIdenaBotDisclosure}
>
<DialogBody>
<Stack>
<Text>
{t(
`MyIdenaBot reminds you about important actions based on your
identity status:`,
{nsSeparator: '!!'}
)}
</Text>
{eitherState(IdentityStatus.Undefined) && (
<IdenaBotFeatureList
features={[
'next validation reminder',
'notification when you get an invite',
'reminder to activate your invite',
'your validation results when validation consensus is reached',
]}
/>
)}
{eitherState(IdentityStatus.Invite, IdentityStatus.Candidate) && (
<IdenaBotFeatureList
features={[
'next validation reminder',
'your validation results when validation consensus is reached',
]}
/>
)}
{eitherState(IdentityStatus.Newbie) && (
<IdenaBotFeatureList
features={[
'next validation reminder',
'reminder to create flips if you haven’t done it yet and the validation is coming',
'your validation results when validation consensus is reached',
]}
/>
)}
{eitherState(IdentityStatus.Verified, IdentityStatus.Human) && (
<IdenaBotFeatureList
features={[
'next validation reminder',
'reminder to create flips',
'your validation results when validation consensus is reached',
'reminder to share your remaining invites',
'reminder to submit extra flips to get more rewards',
'status update of all your invitees to check if they are ready for the validation (activated invites, submitted flips)',
]}
/>
)}
{eitherState(IdentityStatus.Zombie, IdentityStatus.Suspended) && (
<IdenaBotFeatureList
features={[
'next validation reminder',
'your validation results when validation consensus is reached',
'reminder to share your remaining invites',
'reminder to submit extra flips to get more rewards',
'status update of all your invitees to check if they are ready for the validation (activated invites, submitted flips)',
]}
/>
)}
</Stack>
</DialogBody>
<DialogFooter align="center">
<Checkbox
borderColor="gray.100"
isChecked={doNotShowAgain}
onChange={e => {
setDoNotShowAgain(e.target.checked)
}}
>
{t('Do not show again')}
</Checkbox>
<SecondaryButton
onClick={() => {
myIdenaBotDisclosure.onClose()
if (doNotShowAgain) onConnect()
}}
>
{t('Not now')}
</SecondaryButton>
<PrimaryButton
ref={connectButtonRef}
onClick={() => {
openExternalUrl('https://t.me/MyIdenaBot')
onConnect()
}}
>
{t('Connect')}
</PrimaryButton>
</DialogFooter>
</Dialog>
</>
)
}
Example #22
Source File: components.js From idena-web with MIT License | 4 votes |
export function DeactivateMiningDrawer({
isLoading,
delegatee,
canUndelegate,
onDeactivate,
onClose,
...props
}) {
const {t} = useTranslation()
const sizeInput = useBreakpointValue(['lg', 'md'])
const sizeButton = useBreakpointValue(['mdx', 'md'])
const variantPrimary = useBreakpointValue(['primaryFlat', 'primary'])
const variantSecondary = useBreakpointValue(['secondaryFlat', 'secondary'])
const isDelegator = typeof delegatee === 'string'
return (
<AdDrawer isMining={isLoading} onClose={onClose} {...props}>
<DrawerHeader>
<Flex
direction="column"
textAlign={['center', 'start']}
justify={['space-between', 'flex-start']}
>
<Flex
order={[2, 1]}
mt={[6, 0]}
align="center"
justify="center"
bg="blue.012"
h={12}
w={12}
rounded="xl"
>
<UserIcon boxSize={6} color="blue.500" />
</Flex>
<Heading
order={[1, 2]}
color="brandGray.500"
fontSize={['base', 'lg']}
fontWeight={[['bold', 500]]}
lineHeight="base"
mt={[0, 4]}
>
{isDelegator
? t('Deactivate delegation status')
: t('Deactivate mining status')}
</Heading>
</Flex>
</DrawerHeader>
<DrawerBody>
<Stack spacing={6} mt={[2, 30]}>
<Text fontSize={['mdx', 'md']} mb={[0, 3]}>
{isDelegator
? t(`Submit the form to deactivate your delegation status.`)
: t(
`Submit the form to deactivate your mining status. You can activate it again afterwards.`
)}
</Text>
{isDelegator && (
<FormControl as={Stack} spacing={[0, 3]}>
<FormLabel fontSize={['base', 'md']}>
{t('Delegation address')}
</FormLabel>
<Input size={sizeInput} defaultValue={delegatee} isDisabled />
</FormControl>
)}
{isDelegator && !canUndelegate && (
<Alert
status="error"
rounded="md"
bg="red.010"
borderColor="red.050"
borderWidth={1}
>
<AlertIcon name="info" alignSelf="flex-start" color="red.500" />
<AlertDescription
color="brandGray.500"
fontSize="md"
fontWeight={500}
>
{t('You can disable delegation at the next epoch only')}
</AlertDescription>
</Alert>
)}
</Stack>
<PrimaryButton
display={['flex', 'none']}
mt={4}
w="100%"
fontSize="mobile"
size="lg"
isDisabled={isDelegator && !canUndelegate}
isLoading={isLoading}
onClick={onDeactivate}
loadingText={t('Waiting...')}
>
{t('Submit')}
</PrimaryButton>
</DrawerBody>
<DrawerFooter display={['none', 'flex']} mt={[6, 0]} px={0}>
<Flex width="100%" justify={['space-evenly', 'flex-end']}>
<Button
variant={variantSecondary}
order={[3, 1]}
size={sizeButton}
type="button"
onClick={onClose}
>
{t('Cancel')}
</Button>
<Divider
order="2"
display={['block', 'none']}
h={10}
orientation="vertical"
color="gray.100"
/>
<Button
variant={variantPrimary}
order={[1, 3]}
size={sizeButton}
ml={[0, 2]}
isDisabled={isDelegator && !canUndelegate}
isLoading={isLoading}
onClick={onDeactivate}
loadingText={t('Waiting...')}
>
{t('Submit')}
</Button>
</Flex>
</DrawerFooter>
</AdDrawer>
)
}
Example #23
Source File: node.js From idena-web with MIT License | 4 votes |
function Settings() {
const {t} = useTranslation()
const {addNotification} = useNotificationDispatch()
const settingsState = useSettingsState()
const {saveConnection} = useSettingsDispatch()
const size = useBreakpointValue(['lg', 'md'])
const flexDirection = useBreakpointValue(['column', 'row'])
const flexJustify = useBreakpointValue(['flex-start', 'space-between'])
const [state, setState] = useState({
url: settingsState.url || '',
apiKey: settingsState.apiKey || '',
})
const [nodeProvider, setNodeProvider] = useState('')
useEffect(() => {
setState({url: settingsState.url, apiKey: settingsState.apiKey})
}, [settingsState])
const notify = () =>
addNotification({
title: 'Settings updated',
body: `Connected to url ${state.url}`,
})
useEffect(() => {
async function check() {
try {
const result = await checkKey(settingsState.apiKey)
const provider = await getProvider(result.provider)
setNodeProvider(provider.data.ownerName)
} catch (e) {}
}
if (settingsState.apiKeyState === ApiKeyStates.OFFLINE) check()
}, [settingsState.apiKeyState, settingsState.url, settingsState.apiKey])
return (
<SettingsLayout title={t('Node')}>
<Stack
spacing={5}
mt={[3, 8]}
width={['100%', '480px']}
position="relative"
>
{settingsState.apiKeyState === ApiKeyStates.RESTRICTED && (
<Alert
status="error"
bg="red.010"
borderWidth="1px"
borderColor="red.050"
fontWeight={500}
rounded="md"
px={3}
py={2}
>
<AlertIcon name="info" color="red.500" size={5} mr={3}></AlertIcon>
{t(
'The shared node access is restricted. You cannot use the node for the upcoming validation ceremony.'
)}
</Alert>
)}
{settingsState.apiKeyState === ApiKeyStates.OFFLINE &&
!!settingsState.url &&
!!settingsState.apiKey && (
<Alert
status="error"
bg="red.010"
borderWidth="1px"
borderColor="red.050"
fontWeight={500}
rounded="md"
px={3}
py={2}
>
<AlertIcon name="info" color="red.500" size={5} mr={3} />
<Text>
{nodeProvider
? t(
'This node is unavailable. Please contact the node owner:',
{
nsSeparator: 'null',
}
)
: t('Node is unavailable.')}{' '}
{nodeProvider && (
<Link
color="#578fff"
href={`https://t.me/${nodeProvider}`}
target="_blank"
ml={1}
>
{nodeProvider}
</Link>
)}
</Text>
</Alert>
)}
<Flex display={['none', 'flex']} justify="space-between">
<Heading as="h1" fontSize="lg" fontWeight={500} textAlign="start">
{t('Node settings')}
</Heading>
<Box mt="3px">
<Link
color="#578fff"
fontSize="13px"
fontWeight="500"
height="17px"
href="/node/rent"
>
{t('Rent a new node')}
<ChevronDownIcon boxSize={4} transform="rotate(-90deg)" />
</Link>
</Box>
</Flex>
<FormControl
as={Flex}
direction={flexDirection}
justify={flexJustify}
mt={[0, 5]}
>
<Flex justify="space-between">
<FormLabel
fontSize={['base', 'md']}
color={['brandGray.500', 'muted']}
fontWeight={[500, 400]}
mb={[2, 0]}
lineHeight={[6, 8]}
>
{t('Shared node URL')}
</FormLabel>
<Box display={['block', 'none']}>
<Link
fontSize="16px"
fontWeight="500"
color="#578fff"
href="/node/rent"
>
{t('Rent a new node')}
</Link>
</Box>
</Flex>
<Input
id="url"
w={['100%', '360px']}
size={size}
value={state.url}
onChange={e => setState({...state, url: e.target.value})}
/>
</FormControl>
<FormControl as={Flex} direction={flexDirection} justify={flexJustify}>
<FormLabel
fontSize={['base', 'md']}
color={['brandGray.500', 'muted']}
fontWeight={[500, 400]}
mb={[2, 0]}
lineHeight={[6, 8]}
>
{t('Node API key')}
</FormLabel>
<PasswordInput
id="key"
w={['100%', '360px']}
size={size}
value={state.apiKey}
onChange={e => setState({...state, apiKey: e.target.value})}
/>
</FormControl>
{settingsState.apiKeyState === ApiKeyStates.ONLINE && (
<Alert
status="warning"
bg="warning.020"
borderWidth="1px"
borderColor="warning.100"
fontWeight={500}
rounded="md"
px={3}
py={2}
>
<AlertIcon size={5} mr={3} colo="warning.500"></AlertIcon>
{t(
'Please do not use the API key on multiple devices at the same time as this will cause the validation failure.'
)}
</Alert>
)}
<Flex justify="space-between">
<PrimaryButton
size={size}
w={['100%', 'auto']}
onClick={() => {
saveConnection(state.url, state.apiKey, true)
notify()
}}
ml="auto"
>
{t('Save')}
</PrimaryButton>
</Flex>
</Stack>
</SettingsLayout>
)
}
Example #24
Source File: containers.js From idena-web with MIT License | 4 votes |
export function DnaSendFailedDialog({
error,
url,
onRetrySucceeded,
onRetryFailed,
onOpenFailUrl,
...props
}) {
const {t} = useTranslation()
return (
<Dialog closeOnOverlayClick={false} closeOnEsc={false} {...props}>
<DialogBody>
<Stack spacing={5}>
<Alert
status="error"
bg="red.010"
borderRadius="lg"
flexDirection="column"
justifyContent="center"
textAlign="center"
minH={132}
>
<Stack align="center" spacing={1}>
<AlertIcon name="delete" size={10} mr={0} />
<Stack spacing={1}>
<AlertTitle fontSize="lg" fontWeight={500}>
{t('Something went wrong')}
</AlertTitle>
<Text color="muted" wordBreak="break-all">
{error}
</Text>
</Stack>
</Stack>
</Alert>
</Stack>
</DialogBody>
<DialogFooter>
<SecondaryButton
onClick={() => {
const requestedUrl = new URL(url)
handleCallbackUrl(url, 'json', {
// eslint-disable-next-line no-shadow
onJson: ({success, error, url}) => {
if (success) {
onRetrySucceeded({
hash: requestedUrl.searchParams.get('tx'),
url: url ?? requestedUrl.href,
})
} else {
onRetryFailed({
error:
error ??
t('{{url}} responded with an unknown format', {
url: requestedUrl.href,
}),
url: url ?? requestedUrl,
})
}
},
}).catch(error => {
console.error(error)
onRetryFailed({
error: error?.message,
url,
})
})
}}
>
{t('Retry')}
</SecondaryButton>
<PrimaryButton
onClick={() => {
openExternalUrl(url)
onOpenFailUrl()
}}
>
{t('Open in browser')}
</PrimaryButton>
</DialogFooter>
</Dialog>
)
}