@chakra-ui/react#AlertIcon JavaScript Examples
The following examples show how to use
@chakra-ui/react#AlertIcon.
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 |
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 #2
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 #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: 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 #5
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 #6
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 #7
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 #8
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 #9
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 #10
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 #11
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 #12
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 #13
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>
)
}
Example #14
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 #15
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 #16
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>
}